【发布时间】:2013-08-12 09:17:33
【问题描述】:
简介
Scala的Future(new in 2.10和now 2.9.3)是一个应用函子,这意味着如果我们有一个traversable typeF,我们可以取一个F[A]和一个函数A => Future[B]然后转他们变成了Future[F[B]]。
此操作在标准库中作为Future.traverse 可用。 Scalaz 7 还提供了一个更通用的traverse,如果我们从scalaz-contrib library 导入Future 的应用函子实例,我们可以在这里使用它。
这两个traverse 方法在流的情况下表现不同。标准库遍历在返回之前消耗流,而Scalaz的returns the future immediately:
import scala.concurrent._
import ExecutionContext.Implicits.global
// Hangs.
val standardRes = Future.traverse(Stream.from(1))(future(_))
// Returns immediately.
val scalazRes = Stream.from(1).traverse(future(_))
还有另一个区别,正如Leif Warner 观察到的here。标准库的 traverse 立即启动所有异步操作,而 Scalaz 启动第一个,等待它完成,启动第二个,等待它,等等。
流的不同行为
很容易通过编写一个函数来显示第二个差异,该函数将为流中的第一个值休眠几秒钟:
def howLong(i: Int) = if (i == 1) 10000 else 0
import scalaz._, Scalaz._
import scalaz.contrib.std._
def toFuture(i: Int)(implicit ec: ExecutionContext) = future {
printf("Starting %d!\n", i)
Thread.sleep(howLong(i))
printf("Done %d!\n", i)
i
}
现在Future.traverse(Stream(1, 2))(toFuture) 将打印以下内容:
Starting 1!
Starting 2!
Done 2!
Done 1!
还有 Scalaz 版本 (Stream(1, 2).traverse(toFuture)):
Starting 1!
Done 1!
Starting 2!
Done 2!
这可能不是我们想要的。
对于列表呢?
奇怪的是,在这方面,两个遍历在列表上的行为是相同的——Scalaz 不会在开始下一个未来之前等待一个未来完成。
另一个未来
Scalaz 还包含自己的 concurrent 包和自己的期货实现。我们可以使用与上面相同的设置:
import scalaz.concurrent.{ Future => FutureZ, _ }
def toFutureZ(i: Int) = FutureZ {
printf("Starting %d!\n", i)
Thread.sleep(howLong(i))
printf("Done %d!\n", i)
i
}
然后我们得到 Scalaz 在流 for 列表 以及流上的行为:
Starting 1!
Done 1!
Starting 2!
Done 2!
也许不那么令人惊讶的是,遍历无限流仍然会立即返回。
问题
此时我们确实需要一个表格来总结,但必须要做一个列表:
- 带有标准库遍历的流:在返回前消耗;不要等待每个未来。
- 带有 Scalaz 遍历的流:立即返回;请等待每个未来完成。
- 带有流的 Scalaz 期货:立即返回;请等待每个未来完成。
还有:
- 具有标准库遍历的列表:不要等待。
- 带有 Scalaz 遍历的列表:不要等待。
- 带有列表的 Scalaz 期货:请等待每个未来完成。
这有意义吗?列表和流上的此操作是否存在“正确”行为? “最异步”的行为——即在返回之前不消耗集合,并且不等待每个未来完成后再继续下一个——是否有某种原因在这里没有表现出来?
【问题讨论】:
-
在“最佳”情况下,Future.traverse 在流上必须返回一个在请求时创建的 Futures 流(意味着在输出请求时从输入中延迟读取元素)。虽然肯定有可能,但实施起来比较困难。
-
@soulcheck:在这种情况下,
traverse返回一个Future[Stream[B]]——这部分没有争议。问题是语义应该是什么。 -
你是对的,没有正确阅读。我也知道你现在的疑虑来自哪里。
-
你查看过scala的遍历源吗?该死的,那是some ugly scala code。尤其是
for:) -
相关问题和机器学习链接stackoverflow.com/a/17183164/1296806
标签: scala concurrency future scalaz applicative