Clojure - core.async 合并单向通道

Clojure - core.async merge unidirectional channel

我有两个单向 core.async 频道:

因为这是 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/ReadPortcljs.core.async.impl.protocols/WritePort)。

我个人不推荐它。抛开您依赖于实现细节这一事实,我不认为 core.async 通道旨在作为进程的封装,只是作为它们之间的通信点。所以在这个用例中,只需将输入通道传递给生产者,将输出通道传递给消费者。