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

欢迎!请参阅 关于 页面,了解更多操作信息。

0 投票
core.async

当前,在现代浏览器中,(<! (timeout 0)) 将花费大约 4ms,因为它最终变成 (js/setTimeout f 0)。在现代浏览器中,setTimeout 即使是 0 毫秒,也不会小于 4ms,而且 4ms 对于只是想要将控制权返回给浏览器以最短的时间来说是太长了。

参看
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。但这就是我们要避免在 0 毫秒持续时间的情况下的问题。所以我看不出 callOnce 是一个解决方案。

0 投票

评论者:pkobrien

我认为你是对的,Mike。尽管难以置信,因为显然谷歌知道这个问题。但现在我正在重新阅读goog.Timer代码,我没有看到他们在这里修复了它。看起来goog.async.nextTick是唯一的解决方案。

0 投票

评论者:pkobrien

我只想提到这个问题是针对core.async的ClojureScript版本,并且看起来使用(<! (timeout 0))作为暂时将控制权交还给js事件处理的惯用法。因此,我认为使其高效非常重要。

0 投票

评论者:gshayban

在阅读这个“问题”时,看来真正的问题是CLJS(ClojureScript)中有更多样化的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
为了明确...你将这称为引号的“问题”。几乎好像它不是一个问题。

但对我来说,这是一个足够真实的“问题”,我必须要么与分支协作,要么完全放弃使用core.async。

我需要(<! (timeout 0))表示0,或者尽可能接近0。我需要它按照宣传的方式工作。当前的实现并没有达到0(或者尽可能接近0),而是提供了与(<! (timeout 4))相同的结果,而与0ms(或者接近0ms)相比,4ms是完全的永久。每次迭代都需要4ms,一个goloop每秒只能迭代250次。

任何有goloop在监听爆发式websocket输出的人都会有这个问题。他们需要疯狂地处理(不延迟4ms),但也要将控制权交还给浏览器,以便浏览器做一些它需要做的事情。当浏览器页面失去“关注”,进入后台,js被限制,动画帧速度减慢等时,所有这些问题都会加剧。

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 (由mikethompson报告)
...