我想运行像
这样的代码(->> input
(partition-all 5)
(map a-side-effect)
dorun)
异步分割输入和输出(a-side-effect)。
然后我编写了以下实验代码。
;; using boot-clj
(set-env! :dependencies '[[org.clojure/core.async "0.2.374"]])
(require '[clojure.core.async :as async :refer [<! <!! >! >!!]])
(let [input (range 18)
c (async/chan 1 (comp (partition-all 5)
(map prn)))]
(async/onto-chan c input false)
(async/close! c))
此代码的解释:
async/onto-chan
用于将Seq元素(输入片段)放入通道c
并将被多次调用,因此第三个参数为false
。prn
可替代a-side-effect
。我预计上面的代码会打印
[0 1 2 3 4]
[5 6 7 8 9]
[10 11 12 13 14]
[15 16 17]
在REPL中但它不打印任何字符。
然后我加时间等待,就像这样
(let [c (async/chan 1 (comp (partition-all 5)
(map prn)))]
(async/onto-chan c (range 18) false)
(Thread/sleep 1000) ;wait
(async/close! c))
这段代码给出了我的预期输出。
然后我检查core.async/onto-chan
。
我认为发生了什么:
c
频道已core.async/close!
。core.async/onto-chan
的参数中的每一项都被core.async/>!
放在go-loop
onto-chan
中,因为频道c
已关闭。< / LI>
醇>
有确定的方法可以在close!
之前放置项目吗?
写onto-chan
的同步版本而不使用go-loop
?
或者我的想法是错的?
答案 0 :(得分:1)
你的第二个例子Thread.sleep
只有'错误地运作'。
它起作用的原因是来自c
的传感器的每个转换结果值都是nil
,并且因为通道中不允许nil
s,所以会抛出异常,并没有将值放入c
:这是允许生产者onto-chan
继续进入通道而不是阻止等待的原因。如果将第二个示例粘贴到REPL中,您将看到四个堆栈跟踪 - 每个分区一个。
nil
当然是由于映射prn
,这是一个副作用函数,为所有输入返回nil
。
如果我理解你的设计,你的目标就是做这样的事情:
(defn go-run! [ch proc]
(async/go-loop []
(when-let [value (<! ch)]
(proc value)
(recur))))
(let [input (range 18)
c (async/chan 1 (partition-all 5))]
(async/onto-chan c input)
(<!! (go-run! c prn)))
go-loop
消费者。map
和副作用不能很好地结合在一起,所以我将副作用prn
提取到消费者中。onto-chan
不能多次调用(至少在显示的代码中),因此它不需要false
参数。答案 1 :(得分:0)
采取megakorre的想法:
(let [c (async/chan 1 (comp (partition-all 5)
(map prn)))
put-ch (async/onto-chan c (range 18) false)]
(async/alts!! [put-ch])
(async/close! c))