Clojure-Core.async管道+混淆

时间:2018-09-09 00:12:52

标签: asynchronous clojure core.async

我很难理解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。

1 个答案:

答案 0 :(得分:1)

您已将takepipeline放在比赛中。他们俩都从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