简体   繁体   English

Core.async

[英]Core.async <! channel deadlock

Why does Alpha stop early, when I expect it to behave like Beta? 为什么我希望Alpha像Beta一样早停下来? The only difference between Alpha and Beta is >! Alpha和Beta之间的唯一区别是>! and put! put! , as commented below. ,如下所述。

Alpha: Α:

user=> (def q (chan))
#'user/q
user=> (def counter (atom 0))
#'user/counter
user=> (defn mg [event-queue]
  #_=>      (go-loop [event (<! event-queue)]
  #_=>       (swap! counter inc)
  #_=>       (when (< @counter 4)
  #_=>         (println "counter: " @counter)
  #_=>         (>! event-queue {:a @counter})      ;; Here's the only difference
  #_=>         (println "event: " event)
  #_=>         (recur (<! event-queue)))))
#'user/mg
user=> (mg q)
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x3a1ffd56 "clojure.core.async.impl.channels.ManyToManyChannel@3a1ffd56"]
user=> (put! q "hi")
counter:  true
1
user=>

Beta: Beta版:

user=> (def q (chan))
#'user/q
user=> (def counter (atom 0))
#'user/counter
user=> (defn mg [event-queue]
  #_=>   (go-loop [event (<! event-queue)]
  #_=>    (swap! counter inc)
  #_=>    (when (< @counter 4)
  #_=>      (println "counter: " @counter)
  #_=>      (put! event-queue {:a @counter})      ;; Here's the only difference
  #_=>      (println "event: " event)
  #_=>      (recur (<! event-queue)))))
#'user/mg
user=> (mg q)
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x72c9b65a "clojure.core.async.impl.channels.ManyToManyChannel@72c9b65a"]
user=> (put! q "hi")
true
counter:  1
event:  hi
counter:  2
event:  {:a 1}
counter:  3
event:  {:a 2}
user=> 

It's also interesting that, after executing Alpha, the channel #'user/q was properly enqueued: 有趣的是,在执行Alpha之后,通道#'user/q已正确入队:

user=> (take! q println)
event:  hi
{:a 1}
nil
user=> 

The same results occur in both Clojure and Clojurescript. Clojure和Clojurescript都发生相同的结果。 Is this some sort of deadlock, or is the suppose to happen? 这是某种僵局,还是应该发生?

This is expected. 这是预期的。

The channel q is created without a buffer, so when a value is placed with >! 通道q是在没有缓冲区的情况下创建的,因此当用>!放置值时>! , it will block (park) the go-loop until another thread is ready to consume the value with <! ,它将阻塞(停放) go-loop直到另一个线程准备好使用<! .

One way to work around this is to give q a 1-slot buffer with (def q (chan 1)) . 解决此问题的一种方法是为q一个具有(def q (chan 1))的1插槽缓冲区。 The buffer allows 1 value to be placed in the channel without blocking the sender. 缓冲区允许在通道中放置1个值,而不会阻止发送方。

Beta behaves differently because put! Beta的行为有所不同,因为put! is asynchronous wrt. 是异步WRT。 the caller -- it uses a separate thread to place the new value in the channel. 调用者-它使用单独的线程将新值放置在通道中。 This avoids blocking the current go-loop , allowing the channel to be read and progress to continue. 这避免了阻塞当​​前的go-loop ,从而允许读取通道并继续进行操作。

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

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