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

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

0

评论者为:pkobrien

我只是想提到,这个问题是关于core.async的ClojureScript版本,而且看起来使用(<! (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毫秒对于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报告)
...