首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何穷尽通道的值,然后返回结果(ClojureScript)?

如何穷尽通道的值,然后返回结果(ClojureScript)?
EN

Stack Overflow用户
提问于 2016-01-02 05:52:24
回答 3查看 1.1K关注 0票数 4

假设通道chan在队列中具有值"1“和"2”。

目标:创建一个函数,该函数接受chan并返回向量[1 2]。注意,如果这个函数在返回值之前阻塞了一段时间,我完全没问题。

尝试:

代码语言:javascript
复制
(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。

EN

回答 3

Stack Overflow用户

发布于 2016-01-02 06:38:48

您应该使用core.async中的alts!来完成此任务(https://clojure.github.io/core.async/#clojure.core.async/alts!):

代码语言:javascript
复制
(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中没有阻塞读(<!!),您可以通过以下方式重写:

代码语言:javascript
复制
(defn read-all [from-chan]
  (go-loop [res []]
    (let [[v _] (alts! [from-chan] :default :complete)]
      (if (= v :complete)
        res
        (recur (conj res v)))))))

所以它将返回通道,然后从那里读取一个值:

代码语言:javascript
复制
(go (let [res (<! (read-all x))]
      (println res)
      ;; do something else
      ))
票数 6
EN

Stack Overflow用户

发布于 2016-01-02 23:08:32

您可以使用clojure.core.async/reduce

代码语言:javascript
复制
;; 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建议的方法)。

票数 2
EN

Stack Overflow用户

发布于 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事件;同样,您不希望事件侦听器在等待事件发生时阻塞用户界面,也不希望通道在等待新值时阻塞。

相反,请尝试使用每当传递新值时都会调用的回调函数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34560423

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档