【问题标题】:Clojure - core.async merge unidirectional channelClojure - core.async 合并单向通道
【发布时间】:2015-09-24 22:05:32
【问题描述】:

我有两个单向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)

另外,关闭双向通道应该关闭两个底层通道。

有可能吗?

【问题讨论】:

  • 对不起,我没有得到你的用例,也许你可以添加一个你想要的代码示例?
  • @ValentinWaeselynck 我编辑了我的问题,希望现在有意义。
  • 仍然不确定我是否明白:/您在描述中提到了 6 个频道名称(A、B、输入、输出、io、ch)。如果你统一这个会有所帮助
  • @ValentinWaeselynck 是的,正确,已更正:)

标签: clojure clojurescript core.async


【解决方案1】:

如果我正确理解您的用例,我相信您尝试做的只是单渠道工作。

另一方面,如果您尝试为多个通道的组合呈现一个类似于通道的接口(例如,某些进程从in 获取数据,对其进行处理,然后将结果输出到@ 987654323@),那么你总是可以实现正确的protocols(在ClojureScript的情况下,cljs.core.async.impl.protocols/ReadPortcljs.core.async.impl.protocols/WritePort)。

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

【讨论】:

  • 在我的情况下是关于通信的(客户端 -> 服务器和服务器 -> 客户端)。在这种情况下实施这些协议是否更有意义?
  • 啊,所以一个通道用于发送到服务器,另一个用于从服务器读取,对吧?因为你有单向阅读和单向写作并不意味着你应该在同一个端口上做(不要把它们复杂化:))。同样,这些协议不是公共 API 的一部分,依赖它们是危险的。我肯定会选择 2 个频道。
  • 是的,完全正确 :) 我完全明白非公共 API 的意义,但我不确定我明白为什么不应该完成它们?
  • 好吧,如果你这样做了,你为什么会得到好处? OTOH,例如当您想添加更多制作人时,保留 2 个不同的频道可能很有用。
【解决方案2】:

您的示例显示的流程基本如下:

io ---> out-ch ---> worker ---> in-ch ---> io
^-------------------------------------------*

如果我们假设工作者从in-ch 读取并写入out-ch,那么在示例中这两个通道可能是相反的。如果工人反其道而行之,那就对了。为了防止循环,使用非缓冲队列很重要,这样您就不会听到自己的消息回响给自己。

附带说明,没有单向和双向通道之类的东西。取而代之的是缓冲和非缓冲通道。如果我们正在通过缓冲频道交谈,那么当我有话要对您说时,我会停下来,直到您碰巧正在收听该频道,然后一旦您准备好听到它,我就会将我的信息放入频道并且您会收到它。然后为了得到回复,我会一直等待,直到你准备好发送它,一旦你准备好,你把它放在频道上,我从频道里得到它(一次全部)。这感觉就像一个双向通道,尽管实际上只是无缓冲通道恰好以这种方式进行协调。

如果通道被缓冲,那么我可能会从通道中获取我自己的消息,因为我会完成将它放在通道上,然后准备好在你之前接收响应,甚至准备好接收原始消息。如果您需要像这样使用缓冲通道,请使用其中两个,每个方向一个,它们会“感觉”像单向通道。

【讨论】:

  • 谢谢。我应该提到worker 确实是一个服务器,是的,单向通道本身并不存在,但在我的情况下它们必须存在(取决于通信方式)。
  • 也许发送回复频道询问请求的模式适合您的情况,不过只是猜测。
猜你喜欢
  • 2015-07-11
  • 1970-01-01
  • 2015-07-04
  • 2019-02-13
  • 2014-03-20
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 2015-05-07
相关资源
最近更新 更多