并发理解

Concurrent for-comprehensions

据此 blog post 理解可能存在性能问题。例如:

for {
  a <- remoteCallA()
  b <- remoteCallB()
} yield {
  (a, b)
}

remoteCallB 阻塞,直到 remoteCallA 完成。博客 post 建议我们改为这样做:

futureA <- remoteCallA()
futureB <- remoteCallB()
for {
  a <- futureA
  b <- futureB
} yield {
  (a, b)
}

这将确保两个远程调用可以同时启动。

我的问题:以上(以及博客作者)是否正确?

我还没有看到有人使用这种模式,这让我想知道是否有通常使用的替代模式。

谢谢

理解

for {
  a <- remoteCallA()
  b <- remoteCallB()
} yield {
  (a, b)
}

转换为:

remoteCallA().flatmap(a => remoteCallB().map(b => (a,b)))

所以,是的,我相信博主是正确的,因为调用将是顺序的,而不是并发的。

同时执行多个期货的常见模式是使用 zipFuture.traverse。这里有几个例子:

for {
  (a, b) <- remoteCallA() zip remoteCallB()
} yield f(a, b)

当有超过 2 个期货时,这会变得有点麻烦:

for {
  ((a, b), c) <- remoteCall() zip remoteCallB() zip remoteCallC()
} yield (a, b, c)

在这些情况下,您可以使用 Future.sequence:

for {
  Seq(a, b, c) <- 
    Future.sequence(Seq(remoteCallA(), remoteCallB(), remoteCallC()))
} yield (a, b, c)

Future.traverse,如果您有一系列参数,并希望对所有参数应用相同的函数,即 returns a Future.

但这两种方法都有一个问题:如果 Future 中的一个在其他 Future 完成之前提前失败,您自然可能希望结果 Future 在那个时刻立即失败。但事实并非如此。结果 Future 仅在所有期货完成后才失败。有关详细信息,请参阅此问题: