【发布时间】:2015-06-24 09:08:15
【问题描述】:
考虑以下取自example walkthrough of core.async 的代码:
(let [c1 (chan)
c2 (chan)]
(thread
(while true
(let [[v ch] (alts!! [c1 c2])]
(println "Read" v "from" ch))))
(>!! c1 "hi")
(>!! c2 "there"))
我的假设是线程引用了c1 和c2 两个通道,并且基本上会永远运行,试图从其中一个永远不会出现的值中获取值。因此,通道既不会被垃圾收集,线程也不会终止。即使我们明确地close! 通道,线程仍然会继续。我的结论是正确的还是我遗漏了什么?
我之所以这么问,是因为我正试图找到一种方法,让我能够成功地使用这样一个无休止运行的消费者来测试这样的 core.async 代码。我当前的尝试如下所示:
(let [c1 (chan)
c2 (chan)]
(go
(>!! c1 "hi")
(>!! c2 "there"))
(async/thread
(loop [[v ch] (alts!! [c1 c2])]
(println "Read" v "from" ch)
(when-let [[nv nch] (alts!! [c1 c2])]
(if nv
(recur [nv nch])
:done)))))
这会返回一个结果通道(来自thread),我想阻止它获取:done 值,但我需要一种关闭(至少一个)通道的方法。我可以返回两个频道的列表c1, c2 和thread 返回的结果频道,然后close! 例如c1 之后查看结果通道,但这非常难看:
(let [c1 (chan)
c2 (chan)]
(go
(>!! c1 "hi")
(>!! c2 "there"))
[c1 c2 (async/thread
(loop [[v ch] (alts!! [c1 c2])]
(println "Read" v "from" ch)
(when-let [[nv nch] (alts!! [c1 c2])]
(if nv
(recur [nv nch])
:done))))])
=> [#<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@60eb5def> #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@7c64279e> #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@136535df>]
Read hi from #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@60eb5def>
Read there from #<ManyToManyChannel clojure.core.async.impl.channels.ManyToManyChannel@7c64279e>
(let [[c1 c2 resultchan] *1]
(close! c1)
(<!! resultchan))
=>:done
或者,我可能会发送一个特殊的“通信结束”值,然后我可以在接收端进行检查。
这方面的最佳做法是什么样的?
【问题讨论】:
-
go 块是为了与异步函数一起使用(单个!),您正在将它们与同步函数(!!)一起使用,它仍然应该运行但没有多大意义跨度>
-
阻塞 (!!) 和停车 (!) 版本之间的区别更大。在
go块内,两者都是允许的。另外,对于我要解决的问题,我使用>!!还是>!都没有区别。
标签: clojure core.async