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。尽管显然 Google 了解这个问题,但令人难以置信的是,他们在代码中并没有修复它。但现在我重新阅读了 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
为了明确……您将这称为一个“错误”,几乎像它不是一个错误。

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

我需要 (<! (timeout 0)) 等于 0,或者尽可能接近 0。我需要它按宣传的那样工作。当前的实现没有达到 0(或尽可能接近 0),而是与 (<! (timeout 4)) 相同,而 4ms 相比 0ms(或接近 0)是永远的时间。每次迭代 4ms,goloop 只能每秒迭代 250 次。

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

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 提出)
...