我有一个简单的程序:
import scalaz._
import stream._
object Play extends App {
val in1 = io.linesR("C:/tmp/as.txt")
val in2 = io.linesR("C:/tmp/bs.txt")
val p = (in1 merge in2) to io.stdOutLines
p.run.run
}
文件as.txt
包含五个a
,文件bs.txt
包含3个b
。我看到了这种输出:
a
b
b
a
a
b
a
a
a
但是,当我按如下方式更改in2
的声明时:
val in2 = io.stdInLines
然后我得到了我认为的意外行为。根据文档 1 ,程序应根据哪个流更快地提供内容,从每个流中非确定性地提取数据。这应该意味着我看到一堆a
被立即打印到控制台,但这根本不会发生。
的确,在我按ENTER
之前,没有任何反应。很明显,如果我随机选择一个流来获取下一个元素,那么该行为看起来很像我期望的那样,如果该流阻塞,合并的进程也会阻塞(即使其他流包含数据)。
发生了什么事?
1 - 嗯,好的,文档很少,但 Dan Spiewak 在his talk中非常清楚地表示它会抓住任何人是第一个提供数据的人
答案 0 :(得分:6)
问题在于stdInLines
的实施。它是阻塞的,它永远不会Task.fork
是一个线程。
尝试将stdInLines
的实现更改为此实现:
def stdInLines: Process[Task,String] =
Process.repeatEval(Task.apply {
Option(scala.Console.readLine())
.getOrElse(throw Cause.Terminated(Cause.End))
})
原始io.stdInLines
在同一个帖子中运行readLine()
,所以它总是在那里等待,直到你输入内容为止。