3

以下示例改编自 Play Framework 的文档:

val enumerateUsers: Enumerator[String] = {
  Enumerator("Guillaume", "Sadek", "Peter", "Erwan")
}
val consumeOne = Cont[String, String](in =>
  in match {
    case Input.EOF =>
      Done("", Input.Empty)
    case Input.Empty =>
      Done("", Input.Empty)
    case Input.El(s) =>
      Done(s, Input.Empty)
  })
println((enumerateUsers |>> consumeOne).flatMap(_.run).await.get)

打印出来Guillaume

但是,如果我将其更改EnumeratorPushEnumerator

val enumerateUsers: PushEnumerator[String] = Enumerator.imperative[String]()
// consumeOne as before
val i = enumerateUsers |>> consumeOne
enumerateUsers.push("Guillaume")
enumerateUsers.push("Sadek")
enumerateUsers.push("Peter")
enumerateUsers.push("Erwan")
println(i.flatMap(_.run).await.get)
// Timeout exception

我得到了 iteratee 的承诺的超时异常。

为了让它和以前一样,我需要关闭PushEnumerator.

val enumerateUsers: PushEnumerator[String] = Enumerator.imperative[String]()
// consumeOne as before
val i = enumerateUsers |>> consumeOne
enumerateUsers.push("Guillaume")
enumerateUsers.push("Sadek")
enumerateUsers.push("Peter")
enumerateUsers.push("Erwan")
enumerateUsers.close() // <-- magic line
println(i.flatMap(_.run).await.get)

Guillaume和以前一样打印。

我找不到告诉我原因的文档,或者这里的语义差异是什么。有人可以指路吗?

编辑:我在 Play 源代码中找到了我的答案 - 花了一些时间寻找 :) 我会将 @huynhjl 的答案标记为正确,因为他回答了它,但我正在寻找的具体答案非常简单。Play 实现使用副作用来驱动套接字,这并非不合理 - 这不是我所假设的(假设会杀死一切:D)。里面play.core.server.netty.Helpers有一个函数叫做socketOut[A](...). socketOut[A](...)有一个名为 的函数step,它返回一个 Iteratee。e当输入 case 匹配时,此 Iteratee 将写入输出通道El(e)。我的假设是 Iteratees 可以部分消耗 Enumerators 从中您可以获得一个值,但似乎唯一可能发生这种情况的方法是通过副作用......我认为:)

4

1 回答 1

2

对象的作用Enumerator是以特定顺序将元素提供给迭代对象,直到没有更多元素或直到迭代对象完成然后返回该迭代对象。该close()调用指示何时没有更多输入,以便可以返回迭代结果。如果不调用close,可能还会有更多内容需要推送。所以我没有尝试过,但我希望这相当于你的例子:

val i = enumerateUsers |>> consumeOne
i.flatMap(_.run).onRedeem(println) // we will have a result we want to print
// now feed some data
enumerateUsers.push("Guillaume")
enumerateUsers.push("Sadek")
enumerateUsers.push("Peter")
enumerateUsers.push("Erwan")
// no more input, trigger promise computation
enumerateUsers.close() 

如果您应用于enumerateUsers无法提前知道需要多少元素才能获得结果的迭代对象(一般情况),则更有意义。

于 2012-05-17T20:55:02.617 回答