2024 年 Clojure 状态调查中分享你的想法!

欢迎!请在关于页面上查看更多有关此功能的信息。

0
core.async

目前 (<! (timeout 0)) 在现代浏览器中将花费大约 4 毫秒,因为它最终变成了 (js/setTimeout f 0)。在现代浏览器中,即使设置为 0 毫秒,setTimeout 也不可能低于 4 毫秒。如果你只是想将控制权交给浏览器最短的时间,4 毫秒就太长了。

参见
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

评论由:pkobrien

我只是想提一下,这个问题是针对ClojureScript版本的core.async,而且看起来使用(<! (timeout 0))作为临时将控制权传回js事件处理的方式是比较符合语法的。因此,我认为这对提高效率来说非常重要。

0

评论者:gshayban

在阅读这个“错误”时,似乎实际问题是CLJS中有更频繁的goblock分发。这可以/应该得到改善,但改变(<! (timeout 0))--无意义的代码--的行为并不能以有意义的方式解决问题。

我们应从根源上消除这种挂锁的需要,而不是使未定义的行为更加特定。ASYNC-131和ASYNC-43是相关的,可能是更好的起点。

0

评论由:mikethompson

@Ghadi
1. 我看不出问题131是如何与另一个问题紧密相关,足以成为“更好的起点”。它有不同的重点,代表了不同的需求,可能需要不同的解决方案(正如目前的建议所显示的)。

  1. 从David Nolen提出的Google Closure分发的角度来看,问题43几乎看起来可以关闭。顺便说一句,我的建议是确实使用goog.async.nextTick(因此我遵循Google Closure的方法)。

此外,我不同意你的说法,即(<! (timeout 0))是“无意义的代码”。在单线程环境中,如浏览器,有时需要从go循环中明确地将控制权“交还”给浏览器(如果该go循环暂时占用CPU)。目前(<! (timeout 0))是唯一我知道可以这样做的方法。它可以重新改造为(<! (yield-cpu))来使意图更清晰,这可能很好,但我关心的是有可靠的方法让出处理器,而这种方法不一定总是花费4毫秒。我相信这个需求是真实的,非常“有说服力”:-)

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毫秒的延迟),但同时也需要将控制权交回浏览器,这样浏览器就可以偶尔做它需要做的事情。当浏览器页面失去“焦点”,进入后台,javascript被限制,动画帧减速等情况发生时,所有这些问题都会加剧。

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