2024 年 Clojure 调查! 分享您的想法。

欢迎!请参阅 关于 页面以了解有关此页面的更多信息。

0
core.async

目前,在浏览器上 (<! (timeout 0)) 将花费约 4ms,因为它最终变成 (js/setTimeout f 0)。在浏览器上,setTimeout 不会在 4ms 内返回,即使给出了 0。如果你只想将控制权交还给浏览器以最短的时间,那么这个时间就太久了。

参见
https://github.com/clojure/core.async/blob/d073896192fa55fab992eb4c9ea57b86ec5cf076/src/main/clojure/cljs/core/async/impl/timers.cljs#L161-L164

其后是
https://github.com/clojure/core.async/blob/d073896192fa55fab992eb4c9ea57b86ec5cf076/src/main/clojure/cljs/core/async/impl/dispatch.cljs#L35-L36

我想象了这个微小的重写

(defn queue-delay (link: f delay)
(if (= 0 delay)

  (goog.async.nextTick f)      ;;  <---- new path for 0
 (js/setTimeout f delay))      ;;  <---- existing path

11 答案

0

由 pkobrien 发表的评论

我认为使用 goog.Timer.callOnce 可以适用于任何时间,同时也能解决使用 js/setTimeout 的问题。

0

由 mikethompson 发表的评论

从我看到的来看,goog.Timer.callOnce 使用 setTimeout。但这就是我们试图避免的事情,尤其是在 0ms 时长的情况下。因此,我认为 callOnce 不是一个解决方案。

0

由 pkobrien 发表的评论

我想你是正确的,迈克。尽管难以置信,因为很明显Google已经了解到这个问题。但是现在我再次阅读了goog.Timer代码,我发现他们在这里并没有修复它。看起来goog.async.nextTick是唯一的解决方案。

0

由 pkobrien 发表的评论

我只是想提一下,这个问题是关于ClojureScript版本的核心异步(core.async)的,而且看起来以(<! (timeout 0))的方式来暂时将控制权交回js事件处理是很符合规范的。因此,我认为使它高效是非常重要的。

0

评论者:gshayban

在阅读这个“错误”时,似乎实际问题是CLJS中goblock分发的多样性较多。这应该可以/应该得到改进,但是让(<! (timeout 0))——一种无意义的代码——有不同的行为,并没有实质性解决问题。

我们应该从根源上消除这种“黑客技术”的需求,而不是让未定义的行为更具体。ASYNC-131和ASYNC-43是相关的,可能更好的起点。

0

由 mikethompson 发表的评论

@Ghadi
1. 我认为问题131与它不够紧密相关,不能作为“更好的起点”。它有不同的发展方向,代表不同的需求,并且可能需要不同的解决方案(正如当前的建议所证明的)。

  1. 在我看来,问题43似乎可以通过David Nolen提到的切换到Google Closure分发来解决。顺便提一下,我的建议确实使用goog.async.nextTick(因此我遵循了Google Closure的方法)。

此外,我不同意你的说法,认为(<! (timeout 0))是“无意义的代码”。在单线程环境中,比如浏览器,有时需要从go循环中显式地将控制权“交回”浏览器(如果这个go循环在一段时间内占用CPU)。目前,(<! (timeout 0))是唯一我知道的这么做的方式。它可以改写为(<! (yield-cpu))以使意图更清晰,这可能很好,但我关心的是有一种可以让出控制权的方式,它不必总是花费4ms。我相信这种需求是真实的,而且是非常“合理的”:-)

0

由 mikethompson 发表的评论

@Ghadi
为了明确...你在双引号中把这个问题称为“bug”。好像这并不是真正的bug。

但对我来说,这是一个足够真实的“bug”,我不得不选择与分支版本一起使用或者完全放弃使用core.async。

我需要的(<! (timeout 0))要表示0,或者尽可能接近0。我需要它如广告中所说那样工作。当前实现无法达到0(或尽可能接近0),而是提供与 (<! (timeout 4)) 和 4毫秒相比的相同结果,而4毫秒与0毫秒(或接近0毫秒)相比是永恒的。以每次4毫秒的频率,goloop每秒只能迭代250次。

任何使用goloop监听突发型websocket输出的人都会遇到这个问题。他们需要疯狂处理(没有4毫秒的延迟),但同时也要将控制权交回浏览器,以便偶尔执行它需要的操作。当浏览器页面失去“焦点”,进入后台,JavaScript被节流,动画帧减慢等时,所有这些问题都会加剧。

0

由 pkobrien 发表的评论

如果这能帮助任何可能阅读此内容的人,我已经开始使用以下作为临时解决方案

`
(defn yield []
(let [ch (chan)]

(goog.async.nextTick #(close! ch))
ch))

(go
; 一些代码...
(<! (yield)) ;; 但不是 (<! (timeout 0))
...)
`

0

由 mikethompson 发表的评论

这很好!确实提供了一个占位符解决方案。

0

由 mikethompson 发表的评论

在与 halgari 进一步讨论后,我相信这应该被关闭为“不会修复”(我无法找到如何关闭)。

https://www.reddit.com/r/Clojure/comments/5aprn3/in_coreasync_using_timeout_with_0_delay_causes_a/

0
参考:[https://clojure.atlassian.net/browse/ASYNC-137](https://clojure.atlassian.net/browse/ASYNC-137)(由mikethompson报告)
...