Clojure - core.async 合并单向通道
Clojure - core.async merge unidirectional channel
我有两个单向 core.async
频道:
- 频道输出只能
put!
- 频道只能
take!
因为这是 ClojureScript,所以阻塞操作不可用。我想从这两个(输入和输出)通道中创建一个双向(输入输出)通道。
(def in (async/chan))
(def out (async/chan))
(def in-out (io-chan in out)) ;; io or whatever the solution is
(async/put! in "test")
(async/take! ch (fn [x] (println x))) ;; should print "test"
(async/put! ch) ;; put into ch is equivalent to putting into `out`
我试过类似下面的方法(不工作):
(defn io-chan [in-ch out-ch]
(let [io (chan)]
(go-loop []
(>! out-ch (<! io ))
(>! io (<! in-ch))
(recur))
io))
架构可能会有所帮助:
out in-out
---------------> (unused)
<--------------- <---------------
in
----------------> ---------------->
<---------------- (unused)
此外,关闭双向通道应该关闭两个基础通道。
有可能吗?
您的示例显示的流程基本如下所示:
io ---> out-ch ---> worker ---> in-ch ---> io
^-------------------------------------------*
如果我们假设工作人员从 in-ch
读取并写入 out-ch
那么这两个通道在示例中可能是相反的。如果 worker 做相反的事情,那么它是正确的。为了防止循环,使用非缓冲队列很重要,这样您就不会听到自己的消息回传给自己。
附带说明一下,没有单向和双向通道之分。相反,有缓冲和无缓冲通道。如果我们正在通过缓冲频道交谈,那么当我有话要对你说时,我会停下来,直到你碰巧正在收听频道,然后一旦你准备好听到它,我就会将我的消息放入频道,你就会收到它。然后为了获得响应,我会停放,直到您准备好发送它,一旦您准备好,您将它放在频道上,然后我从频道中获取(一次全部)。这感觉就像一个双向通道,尽管实际上只是无缓冲通道恰好以这种方式协调。
如果通道被缓冲,那么我可能会从通道返回我自己的消息,因为我会完成将它放到通道上,然后在您甚至准备好接收原始消息之前准备好接收响应。如果你需要像这样使用缓冲通道,那么使用其中两个,每个方向一个,它们将 "feel" 像单向通道。
如果我对您的用例理解正确,我相信您要做的只是单通道工作。
另一方面,如果您要做的是为多个通道的组合呈现类似通道的界面(例如,某些进程从 in
获取数据,对其进行处理,然后输出结果为 out
),那么你总是可以实现正确的 protocols(在 ClojureScript 的情况下,cljs.core.async.impl.protocols/ReadPort
和 cljs.core.async.impl.protocols/WritePort
)。
我个人不推荐它。抛开您依赖于实现细节这一事实,我不认为 core.async 通道旨在作为进程的封装,只是作为它们之间的通信点。所以在这个用例中,只需将输入通道传递给生产者,将输出通道传递给消费者。
我有两个单向 core.async
频道:
- 频道输出只能
put!
- 频道只能
take!
因为这是 ClojureScript,所以阻塞操作不可用。我想从这两个(输入和输出)通道中创建一个双向(输入输出)通道。
(def in (async/chan))
(def out (async/chan))
(def in-out (io-chan in out)) ;; io or whatever the solution is
(async/put! in "test")
(async/take! ch (fn [x] (println x))) ;; should print "test"
(async/put! ch) ;; put into ch is equivalent to putting into `out`
我试过类似下面的方法(不工作):
(defn io-chan [in-ch out-ch]
(let [io (chan)]
(go-loop []
(>! out-ch (<! io ))
(>! io (<! in-ch))
(recur))
io))
架构可能会有所帮助:
out in-out
---------------> (unused)
<--------------- <---------------
in
----------------> ---------------->
<---------------- (unused)
此外,关闭双向通道应该关闭两个基础通道。
有可能吗?
您的示例显示的流程基本如下所示:
io ---> out-ch ---> worker ---> in-ch ---> io
^-------------------------------------------*
如果我们假设工作人员从 in-ch
读取并写入 out-ch
那么这两个通道在示例中可能是相反的。如果 worker 做相反的事情,那么它是正确的。为了防止循环,使用非缓冲队列很重要,这样您就不会听到自己的消息回传给自己。
附带说明一下,没有单向和双向通道之分。相反,有缓冲和无缓冲通道。如果我们正在通过缓冲频道交谈,那么当我有话要对你说时,我会停下来,直到你碰巧正在收听频道,然后一旦你准备好听到它,我就会将我的消息放入频道,你就会收到它。然后为了获得响应,我会停放,直到您准备好发送它,一旦您准备好,您将它放在频道上,然后我从频道中获取(一次全部)。这感觉就像一个双向通道,尽管实际上只是无缓冲通道恰好以这种方式协调。
如果通道被缓冲,那么我可能会从通道返回我自己的消息,因为我会完成将它放到通道上,然后在您甚至准备好接收原始消息之前准备好接收响应。如果你需要像这样使用缓冲通道,那么使用其中两个,每个方向一个,它们将 "feel" 像单向通道。
如果我对您的用例理解正确,我相信您要做的只是单通道工作。
另一方面,如果您要做的是为多个通道的组合呈现类似通道的界面(例如,某些进程从 in
获取数据,对其进行处理,然后输出结果为 out
),那么你总是可以实现正确的 protocols(在 ClojureScript 的情况下,cljs.core.async.impl.protocols/ReadPort
和 cljs.core.async.impl.protocols/WritePort
)。
我个人不推荐它。抛开您依赖于实现细节这一事实,我不认为 core.async 通道旨在作为进程的封装,只是作为它们之间的通信点。所以在这个用例中,只需将输入通道传递给生产者,将输出通道传递给消费者。