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。但我们是故意避免在 0 毫秒时长的案例中使用它的。所以我认为 callOnce 不是解决方案。

0

评论由:pkobrien 完成

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

0
by

评论由:pkobrien 完成

我只想提到,这个问题是针对core.async的ClojureScript版本,而且似乎使用(<! (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占用中明确地将控制权交回浏览器(如果该go循环在一段时间内占用CPU)。目前(<! (timeout 0))是我知道的唯一方法。它可以重新工作为(<! (yield-cpu))以使其意图更清晰,这将很好,但我在乎的是有一个不需要每次都花费4ms的交出方式。我相信这个需求是真实存在的,是非常“有意义”的:-)

0
by

评论由:mikethompson 完成

@Ghadi
为了明确……你用引号引用了这被称为“错误”,这似乎就像它不是一个错误。

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

我需要(<! (timeout 0))表示0,或者尽可能接近0。我需要它按广告宣传的那样工作。当前的实现没有达到0(或接近0),而代替提供了与(<! (timeout 4))相同的结果,而4ms相对于0ms(或接近它)就是永远。每次循环4ms,goloop每秒只能迭代250次。

任何监听爆发式websocket输出的goloop都会遇到这个问题。他们需要疯狂处理(没有4ms延迟)但同时也需要将控制权交还给浏览器,以便浏览器执行它所需要的操作。当浏览器页面失去“焦点”,进入后台,js被节流,动画帧变慢等情况时,所有这些问题都会加剧。

0
by

评论由:pkobrien 完成

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

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

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

(go
; 一些代码...
(<! (yield)) ;; 用(<! (timeout 0))代替
...)
`

0
by

评论由:mikethompson 完成

这太好了!当然提供了一个占位符解决方案。

0
by

评论由:mikethompson 完成

在与halgari进一步讨论后,我相信这个问题应该被标记为“不会修复”(我搞不懂如何关闭)。

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

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