简体   繁体   English

Clojure - core.async 合并单向通道

[英]Clojure - core.async merge unidirectional channel

I have two unidirectional core.async channels :我有两个单向core.async通道:

  • channel out can only put!通道出来只能put!
  • channel in can only take!通道内只能take!

And since this is ClojureScript the blocking operations are not available.因为这是 ClojureScript,所以阻塞操作不可用。 I would like to make one bidirectional (in-out) channel out of those two (in and out).我想从这两个(输入和输出)通道中创建一个双向(输入-输出)通道。

  (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`

I tried something like the following (not working) :我尝试了如下(不工作):

(defn io-chan [in-ch out-ch]
  (let [io (chan)]
    (go-loop []
      (>! out-ch (<! io ))
      (>! io (<! in-ch))
      (recur))
    io))

A schema might help :模式可能会有所帮助:

    out                              in-out
 ---------------> (unused)         
 <---------------             <---------------

   in
---------------->             ---------------->
<---------------- (unused)

Also, closing the bidirectional channel should close both underlying channels.此外,关闭双向通道应该关闭两个底层通道。

Is is possible ?有可能吗?

Your example shows a flow basicly like this:您的示例显示的流程大致如下:

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

If we assume that worker reads from in-ch and writes to out-ch then perhaps these two channels are reversed in the example.如果我们假设 worker 从in-ch读取并写入out-ch那么在示例中这两个通道可能颠倒了。 if worker does the opposite then it's correct.如果工人做相反的事情,那么它是正确的。 in order to prevent loops it's important that you use non-buffered queues so you don't hear your own messages echoed back to yourself.为了防止循环,使用非缓冲队列很重要,这样您就不会听到自己的消息回响给自己。

as a side note, there is no such thing as unidirectional and bi-directional channels.作为旁注,没有单向和双向通道这样的东西。 instead there are buffered and unbufferd channels.相反,有缓冲和无缓冲通道。 If we are talking over a buffered channel then when I have something to say to you, I park until you happen to be listening to the channel, then once you are ready to hear it I put my message into the channel and you receive it.如果我们在一个缓冲的频道上交谈,那么当我有话要对你说时,我会停下来,直到你碰巧在听这个频道,然后一旦你准备好听到它,我就把我的消息放到这个频道中,你就会收到它。 Then to get a response I park until you are ready to send it, and once you are, you put it on the channel and I get it from the channel (all at once).然后为了得到回应,我会停在你准备好发送它之前,一旦你准备好发送它,你就把它放在频道上,我从频道中得到它(一次全部)。 This feels like a bi-directional channel though it's really just that unbuffered channels happen to coordinate this way.这感觉就像一个双向通道,尽管它实际上只是无缓冲通道恰好以这种方式进行协调。

If the channel if buffered then I might get my own message back from the channel, because I would finish putting it on the channel and then be ready to receive the response before you where even ready to receive the original message.如果通道被缓冲,那么我可能会从通道返回我自己的消息,因为我会完成将它放在通道上,然后准备好在你准备好接收原始消息之前接收响应。 If you need to use buffered channels like this then use two of them, one for each direction and they will "feel" like uni-directional channels.如果您需要像这样使用缓冲通道,则使用其中的两个,每个方向一个,它们会“感觉”像单向通道。

If I understand your use case right, I believe what you're trying to do is just a one-channel job.如果我理解你的用例是正确的,我相信你想要做的只是一个单通道的工作。

On the other hand, if what you're trying to do is to present a channel-like interface for a composite of several channels (eg some process takes data from in , processes it, and outputs the result to out ), then you could always implement the right protocols (in the case of ClojureScript, cljs.core.async.impl.protocols/ReadPort and cljs.core.async.impl.protocols/WritePort ).另一方面,如果您想要做的是为多个通道的组合呈现类似通道的界面(例如,某些进程从in获取数据,对其进行处理,然后将结果输出到out ),那么您可以始终实现正确的协议(在 ClojureScript 的情况下, cljs.core.async.impl.protocols/ReadPortcljs.core.async.impl.protocols/WritePort )。

I would personnaly not recommend it.我个人不会推荐它。 Leaving aside the fact that you'd be relying on implementation details, I don't believe core.async channels are intended as encapsulation for processes, only as communication points between them.撇开您依赖实现细节的事实不谈,我不认为 core.async 通道旨在作为进程的封装,而只是作为它们之间的通信点。 So in this use case, just pass the input channel to producers and the output channel to consumers.所以在这个用例中,只需将输入通道传递给生产者,将输出通道传递给消费者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM