以下示例改编自 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
。
但是,如果我将其更改Enumerator
为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")
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 从中您可以获得一个值,但似乎唯一可能发生这种情况的方法是通过副作用......我认为:)