2024 Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面以获取更多关于如何工作的信息。

0
core.async

目前,(<! (timeout 0))在现代浏览器中大约需要4ms才能完成,因为它最终会变成(js/setTimeout f 0)。在现代浏览器中,即使设置为0,setTimeout也不会在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。但是,这确实是我们在0ms持续时间的情况下想要避免的情况。因此,我认为callOnce不是一个解决方案。

0

评论由:pkobrien 创建

我认为你说得对,Mike。虽然很难相信,但显然谷歌知道这个问题。但现在我正在重新阅读goog.Timer代码,我发现他们并没有在这里修复它。看起来goog.async.nextTick是唯一可行的解决方案。

0
by

评论由:pkobrien 创建

我只想提一下,这个问题是关于ClojureScript版本的core.async的,并且它似乎非常适合用(<! (timeout 0))的方式来暂时让出控制权给js事件处理。所以我认为使其高效非常重要。

0
by

评论者:gshayban

在阅读这个“错误”时,似乎实际问题是CLJS中的goblock分发更加多样化。它可以/应该得到改进,但是让(<! (timeout 0))——不合理的代码——以不同的方式行为并未真正解决这个问题的实质。

我们应该从根源上去除这种黑客手段的需求,而不是使未定义的行为更加具体。ASYNC-131和ASYNC-43是相关的,可能是更好的起点。

0
by

评论由: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
by

评论由:mikethompson 创建

@Ghadi
为了清楚起见...你用引号来指这个为“错误”。几乎像它不是一个错误。

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

我需要 (<! (timeout 0)) 表示 0,或者尽可能接近 0。我需要它按照广告宣传的来工作。当前的实现并没有达到 0(或尽可能接近 0),而是与 (<! (timeout 4)) 一样,4 毫秒与 0 毫秒(或尽可能接近 0)相比是“永远”。每次循环 4 毫秒,一个 goloop 每秒只能迭代 250 次。

任何有一个 goloop 去监听突发式 websocket 输出的人都会遇到这个问题。他们需要疯狂地进行处理(没有 4 毫秒的延迟),但同时也需要返回控制权,让浏览器完成它需要做的事情,每隔一段时间做一次。当浏览器页面失去“焦点”、进入后台并且 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 报告)
...