[英]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.