2024 Clojure 状态调查! 中分享您的看法。

欢迎!请参阅 关于 页面以获取更多关于该功能的信息。

0
core.async

目前,由于最终表现为 (js/setTimeout f 0),在现代浏览器上 (<! (timeout 0)) 将会消耗大约 4ms。即使在给定时长为 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。虽然很难相信,因为很明显谷歌知道了这个问题。但现在我正在重新阅读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. 这几乎看起来像是David Nolen提到的切换到Google Closure分派就能关闭问题43。顺便说一下,我的建议确实是使用goog.async.nextTick(因此我遵循Google Closure的方法)。

此外,我不同意你的说法,即(<! (timeout 0))是“无意义的代码”。在单线程环境,如浏览器中,有时需要在go循环中从内部明确地将控制权“交回”给浏览器(如果该go循环在一段时间内占用CPU)。目前(<! (timeout 0))是我知道的唯一方法。它可以重新设计为(<! (yield-cpu))以使意图更清晰,这可能很好,但我关心的是有 一种让步方式,不必每次都花费4ms。我相信这种需求是真实的,也是非常“合理”:-)

0
by

由 mikethompson 发表的评论

@Ghadi
为了明确起见……你用引号提到了这“错误”。几乎像它不是错误一样。

但对我来说,这确实是一个足够真实的“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 发表的评论

在与helry讨论后,我相信这个问题应该标记为“不会修复”(我找不到如何关闭它的方法)。

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