Scala异步/等待和并行化

San*_*ete 37 asynchronous scala future async-await

我正在学习在Scala中使用async/await.我在https://github.com/scala/async中看过这个

从理论上讲,这段代码是异步的(非阻塞),但它没有并行化:

def slowCalcFuture: Future[Int] = ...             
def combined: Future[Int] = async {               
   await(slowCalcFuture) + await(slowCalcFuture)
}
val x: Int = Await.result(combined, 10.seconds)    
Run Code Online (Sandbox Code Playgroud)

而另一个是并行化的:

def combined: Future[Int] = async {
  val future1 = slowCalcFuture
  val future2 = slowCalcFuture
  await(future1) + await(future2)
}
Run Code Online (Sandbox Code Playgroud)

它们之间的唯一区别是使用中间变量.这怎么会影响并行化?

Pat*_*iek 49

由于它与async & awaitC#类似,也许我可以提供一些见解.在C#中Task,可以等待的一般规则应该是"热",即已经运行.我假设它在Scala中是相同的,Future从函数返回的函数不必显式启动,但在被调用后只是"运行".如果不是这样,那么以下是纯粹的(可能不是真的)推测.

让我们分析第一种情况:

async {
    await(slowCalcFuture) + await(slowCalcFuture)
}
Run Code Online (Sandbox Code Playgroud)

我们到达那个街区并点击第一个等待:

async {
    await(slowCalcFuture) + await(slowCalcFuture)
    ^^^^^
}
Run Code Online (Sandbox Code Playgroud)

好的,所以我们异步等待计算完成.当它完成后,我们继续分析块:

async {
    await(slowCalcFuture) + await(slowCalcFuture)
                            ^^^^^
}
Run Code Online (Sandbox Code Playgroud)

第二个等待,所以我们异步等待第二次计算完成.完成后,我们可以通过添加两个整数来计算最终结果.

正如你所看到的,我们正在一步一步地等待,等待Future它们一个接一个地出现.

我们来看看第二个例子:

async {
  val future1 = slowCalcFuture
  val future2 = slowCalcFuture
  await(future1) + await(future2)
}
Run Code Online (Sandbox Code Playgroud)

好的,所以这是(可能)发生的事情:

async {
  val future1 = slowCalcFuture // >> first future is started, but not awaited
  val future2 = slowCalcFuture // >> second future is started, but not awaited
  await(future1) + await(future2)
  ^^^^^
}
Run Code Online (Sandbox Code Playgroud)

然后我们正在等待第一个Future,但两个期货目前正在运行.当第一个返回时,第二个可能已经完成(因此我们将立即获得结果)或者我们可能需要等待一段时间.

现在很明显,第二个例子并行运行两个计算,然后等待它们两个完成.两者都准备好后,它会返回.第一个示例以非阻塞方式运行计算,但是按顺序运行.


Mik*_*kha 24

如果有点难以理解,Patryk的答案是正确的.主要的事情,了解有关异步/等待是,它做的只是另一种方式FutureflatMap.幕后没有并发魔法.异步块内的所有电话都是连续的,其中的await实际上不阻止执行的线程,而是包裹异步块的其余部分在关闭,并将其作为一个在完成回调Future,我们正在等待.所以在第一段代码中,第二次计算直到第一次await完成才开始,因为之前没有人开始它.