【问题标题】:Scala Play `Enumerators`: push or pull?Scala Play `Enumerators`:推还是拉?
【发布时间】:2014-07-13 01:10:31
【问题描述】:
我真的很难理解 Play 的 Iteratees 和 Enumerators 的基本目的。
我读过
我读了这个answer,发现它不是像InputStream那样依赖拉模型,而是使用推模型。
迭代器是一种有趣的野兽——一方面,它将数据“推送”到处理程序,而不是依赖处理程序来提取数据,因此具有更好的性能。另一方面,它允许处理程序控制何时应该停止流。
但是 Play 在 Iteratees 上的文档说
或更一般地,使用Enumerator.fromStream 枚举java.io.InputStream。请务必注意,在应用此 Enumerator 的迭代对象准备好接受更多输入之前,不会读取输入。
等等……那到底是怎么回事?
数据是由Enumerator 推送还是由Iteratee 拉取? (即谁来决定何时计算更多数据)
【问题讨论】:
标签:
scala
playframework
iterate
【解决方案1】:
两者兼而有之。流的两端完全不阻塞。
Enumerator 在Iteratee 准备好接收数据之前不会推送任何数据,并且在Iteratee 表示它准备好接收更多数据之前它不会推送更多数据。同时,Enumerator 可以根据需要推送数据。两个进程都不会阻塞另一个进程。
Iteratee 上的这种方法对于理解其工作原理至关重要:
abstract def fold[B](folder: (Step[E, A]) ⇒ Future[B])(implicit ec: ExecutionContext): Future[B]
这是Iteratee中唯一的抽象方法,唯一必须实现的。其余所有方法均根据fold 定义。当Enumerator 应用于Iteratee 时,它会调用此方法,提供folder,这实际上是一个回调。一旦Iteratee 准备就绪,它会调用folder 提供它当前所处的状态,Cont 如果它可以接收更多数据,Done 如果它不再需要,或者Error 如果有出错了。由于folder 返回一个Future,如果Iteratee 处于Cont 状态,它可能需要提供进一步的输入。