下面的例子,改編自遊戲框架的文檔:爲什麼Play的PushEnumerator需要在迭代器完成之前關閉()?
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
。
我無法找到能夠告訴我爲什麼的文檔,或者這裏存在什麼語義差異。有人可以指點道路嗎?
編輯:我發現我的播放源的答案 - 它採取了一些狩獵:)我會紀念@ huynhjl的答案是正確的,因爲他有點回答了這個問題,但我一直在尋找具體的答案非常簡單。 Play實現使用副作用來驅動套接字,這並非不合理 - 這不是我所假設的(假設會殺死所有的東西:D)。在play.core.server.netty.Helpers
裏面有一個叫socketOut[A](...)
的函數。 socketOut[A](...)
具有稱爲step
的函數,該函數返回一個Iteratee。當輸入案例匹配El(e)
時,此迭代器將e
寫入輸出通道。我的假設是,迭代器可以部分使用可以從中獲得價值的統計員,但似乎唯一可能發生的方式是通過副作用...我認爲:)
我將不得不嘗試挖掘Play源代碼,因爲我不清楚這是如何與WebSocket一起工作的。據我記得(我不是在正確的終端ATM),我保持'推'到WebSocket的出站枚舉。我不需要「關閉」它來讓它在線上產生東西,但每個「推」似乎都產生了。如果是這樣的話,那麼我就錯過了一些機制。 –
@DerekWyatt,從技術上講,只要元素被推送,WebSocket可能不必提取迭代器的結果。所以可能這就是爲什麼沒有必要。 – huynhjl
在我的問題結尾添加了我的發現。 –