假设通道chan
在队列中具有值"1“和"2”。
目标:创建一个函数,该函数接受chan
并返回向量[1 2]
。注意,如果这个函数在返回值之前阻塞了一段时间,我完全没问题。
尝试:
(defn chan->vector
[chan]
(let [a (atom true) v []]
(while (not-nil? @a)
(go
(reset! a (<! chan))
(into v @a)
(reset! a (<! chan))
)
) v
)
)
结果: My REPL冻结,并最终输出一个巨大的错误。我逐渐意识到这是因为(go ...)
块是异步的,因此立即返回。因此,我的(while ...)
循环中的原子循环永远不会有机会被设置为nil
,并且循环永远不会终止。
那么我该如何实现预期的结果呢?如果相关,我使用ClojureScript和目标nodejs。
发布于 2016-01-02 06:38:48
您应该使用core.async
中的alts!
来完成此任务(https://clojure.github.io/core.async/#clojure.core.async/alts!):
(def x (chan 10))
(go (>! x 1)
(>! x 2)
(>! x 3))
(defn read-all [from-chan]
(<!! (go-loop [res []]
(let [[v _] (alts! [from-chan] :default :complete)]
(if (= v :complete)
res
(recur (conj res v)))))))
(read-all x)
;; output: [1 2 3]
(read-all x)
;; output: []
(go (>! x 10)
(>! x 20)
(>! x 30)
(>! x 40))
(read-all x)
;; output: [10 20 30 40]
在go-loop
中,此(a/alts! [from-chan] :default :complete)
尝试从通道中读取任何值,如果当前没有可用的值,它将立即发出默认值,因此您将看到应该中断循环并返回累加值。
更新:由于cljs中没有阻塞读(<!!
),您可以通过以下方式重写:
(defn read-all [from-chan]
(go-loop [res []]
(let [[v _] (alts! [from-chan] :default :complete)]
(if (= v :complete)
res
(recur (conj res v)))))))
所以它将返回通道,然后从那里读取一个值:
(go (let [res (<! (read-all x))]
(println res)
;; do something else
))
发布于 2016-01-02 23:08:32
您可以使用clojure.core.async/reduce
;; demo setup
(def ch (async/chan 2))
(async/>!! ch :foo)
(async/>!! ch :bar)
;; background thread to print reduction result
(async/thread
(prn (async/<!! (async/reduce conj [] ch))))
;; closing the channel…
(async/close! ch)
;; …terminates the reduction and the result gets printed out:
;; [:foo :bar]
clojure.core.async/reduce
返回一个通道,当原始通道关闭时,该通道将产生一个值。在内部,它使用go
块,并在从原始通道获取元素之间释放控制。
如果您希望在经过一段时间后生成一个值,而不管原始通道是否关闭,您可以将原始通道包装在传递通道中,该通道将在超时后自动关闭,也可以使用自定义方法执行缩减步骤(可能是@leetwinski建议的方法)。
发布于 2019-05-21 08:45:24
虽然在Clojure和许多其他语言中都可以实现,但在ClojureScript中不可能实现您想要的操作。
你想要一个在监听频道时阻塞的函数。然而,ClojureScript的core.async doesn't include the blocking operators版本。为什么?因为ClojureScript不会阻塞。
我找不到可靠的消息来源来支持最后一句话。在网络上似乎有很多关于这个话题的困惑。然而,我很确定我在说什么,因为ClojureScript最终变成了JavaScript,这就是JavaScript的工作方式。
事实上,JavaScript never blocks既不是在浏览器上,也不是在in Node.js上。为什么?据我所知,它使用单线程,所以如果它被阻塞,用户将无法在浏览器中执行任何操作。
所以不可能做你想做的事。这是故意的,因为它可能会产生灾难性的UX效果。ClojureScript通道类似于JavaScript事件;同样,您不希望事件侦听器在等待事件发生时阻塞用户界面,也不希望通道在等待新值时阻塞。
相反,请尝试使用每当传递新值时都会调用的回调函数。
https://stackoverflow.com/questions/34560423
复制相似问题