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。但这是我们试图避免的情况,特别是对于 0ms 的时间段。所以我不认为 callOnce 是一个解决方案。

0

评论由:pkobrien 提出

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

0

评论由:pkobrien 提出

我想只是提一下,这个问题是关于core.async的ClojureScript版本,而且看来使用(<! (timeout 0))作为暂时将控制权交还给js事件处理的方式,这似乎是相当典型的。所以我认为让这一点更加高效是非常重要的。

0

评论者:gshayban

在阅读这个“错误”时,发现实际的问题是在CLJS中有更多样化的goblock调度。可以/应该改进,但改变(<! (timeout 0))——一个无意义的代码——的做法并不能 meaningful地解决这个问题。

我们应该从根本上消除这个舞弊的必要性,而不是使未定义的行为更加具体。ASYNC-131和ASYNC-43是相关的,可能更好的起点。

0

评论由:mikethompson 提出

@Ghadi
1. 我认为问题131与作为“更好的起点”的关系并不足够紧密。它有不同的重点,代表不同的需求,并且可能会有不同的解决方案(如下面的建议所示)。

  1. 几乎看起来,Issue 43将会随着大卫·诺伦(David Nolen)提到的Google Closure调度方案的更改而被关闭。顺便说一下,你将注意到,我确实建议使用goog.async.nextTick(因此我遵循Google Closure的方法)。

此外,我不同意你关于(<! (timeout 0))是“无意义代码”的说法。在单线程环境(如浏览器)中,有时需要从go循环中明确地将“控制权交回”给浏览器(如果该go循环在一段时间内抢占了CPU)。目前(<! (timeout 0))是唯一的我知道可以实现这一点的办法。它可以重构为(<! (yield-cpu)),以使意图更清晰,这可能很棒,但我在乎的是拥有一种总是不需要花费4毫秒的让出方式。我相信这种需求是真实的,非常“有意义”:-)

0

评论由:mikethompson 提出

@Ghadi
为了澄清……你用引号提到这被称之为“错误”。这似乎几乎不是在称其为错误。

然而对我来说,这确实是一个足够真实的“bug”,我必须选择与分叉版本一起工作或者完全放弃使用core.async。

我需要一个(<! (timeout 0))能够表示0,或者尽可能接近0。我需要它按照广告中所描述的方式工作。当前的实现并没有达到0(或尽可能接近0),而是与(<! (timeout 4))相同,而4毫秒相对于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报告)
...