假设 channel 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
)
)
结果: 我的 REPL 卡住并最终吐出一个巨大的错误。我开始意识到这是因为 (go ...)
block 是异步的,所以会立即返回。因此,我的 (while ...)
循环中的原子永远不会有机会被设置为 nil
并且循环永远不会终止。
那么如何才能达到预期的效果呢?如果相关,我正在使用 ClojureScript 并以 nodejs 为目标。
最佳答案
你应该使用alts!
来自 core.async
完成这个任务
( 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)
尝试从 channel 读取任何值,如果立即没有可用值,它会发出默认值,因此您会看到您应该打破循环并返回累积值。
更新:由于cljs中没有blocking read ( <!!
),你可以重写如下:
(defn read-all [from-chan]
(go-loop [res []]
(let [[v _] (alts! [from-chan] :default :complete)]
(if (= v :complete)
res
(recur (conj res v)))))))
所以它将返回 channel ,然后只从那里读取一个值:
(go (let [res (<! (read-all x))]
(println res)
;; do something else
))
关于node.js - 如何耗尽 channel 的值然后返回结果(ClojureScript)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34560423/