我很难理解Clojure异步库中一个非常简单的概念。我实质上是使用管道创建两个通道,其中使用输入通道的take函数创建输出通道。
据我所知,采取的目的是限制通道在关闭自身之前将收到的项目数(如果此时尚未关闭输入通道)。但是,我一直在玩的代码示例并没有产生预期的结果。
以下面的代码为例:
(def in (chan 1))
(def out (async/take 5 in 1))
(doseq [i (range 10)]
(go (>! in i)))
(pipeline 4 out (filter even?) in)
(go-loop []
(when-some [val (<! out)]
(println val)
(recur))))
我希望发生的事情是,管道将过滤掉奇数,并且仅将偶数传递到“ out”通道,而当out通道收到5个偶数时,它将关闭。但是我看到的是在REPL上打印的是奇数和偶数,如下所示:
2 7 4 0 8 6
此时,out通道仍未关闭,第二次运行doseq将在最终关闭之前打印一些其他值。
我对这里发生的事情感到非常困惑,在使用take而不是管道时它像一种魅力,在不使用take但仍在使用管道时它也可以工作,两者结合使用是完全不同的故事似乎。我在这里错过明显的东西吗?抱歉,如果这是一个简单的错误,这是我第一次(虽然很幼稚)尝试使用core.async。
答案 0 :(得分:1)
您已将take
和pipeline
放在比赛中。他们俩都从in
获取物品并将其添加到out
。替换out
的定义:
(def out (async/chan 3))
例如,并获得预期的结果 在21:24:14.403(运行时间:0.063s)完成
0
2
4
6
8
如果您真的想使用async/take
,可以这样做:
(def first (async/chan 1))
(def second (async/chan 3))
(pipeline 4 second (filter even?) first)
(def third (async/take 3 second))
(defn run []
(go
(doseq [i (range 10)]
(>! first i)))
(go (loop []
(when-some [val (<! third)]
(println val)
(recur)))))
结果:
0
2
4