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

欢迎!请参阅 关于 页面以了解更多关于如何使用本网站的详细信息。

+4
Refs, agents, atoms
已关闭

如果当前正在处理 delay,调用 realized? 会导致调用者阻塞,直到延迟完成并返回 true。

我预期的行为应该是返回 false,这与 futures 的情况一致。毕竟,如果你想要等待它完成,你会调用 deref

(似乎也没有与并发编程相关的标签或分类,但是因为 delay 是 clojure.core 的一部分,我假设这是提问的正确地方)

标记为 在 1.11.0-alpha2 中修复

2 个回答

+1
感谢你这么快就处理这个问题,Alex。

昨天我还发现,在REPL中尝试打印执行延迟的值,如果不取消引用它,也会阻塞。然而,我99%确信这只是因为构建字符串表示的代码也调用了"realized?",所以我认为这不是一个不同的错误。

编辑了
根据realized?的文档字符串,我同意如果延迟正在执行,返回false是正确的行为。然而,确实有在并发环境中使用延迟和realized?知道"延迟是否已经被强制执行?"的情况,以决定是否要替换延迟(在原子中)或等待正在执行的过程完成。我可以使用deref来做到这一点,除了我不想启动尚未开始执行的过程。

如果我的理解正确,在1.11之后,我将不能再使用realized?来检测这种情况。是否将有一种支持的方式来回答"延迟是否已经被强制执行?",还是我现在需要创建自己的结构?

在deref中同步块被进入时(但在thunk开始/完成之前),将变为true/对所有线程可见的第二个isForced() / forced?谓词将是解决我提出的问题的一个可能解决方案。
我认为你想要的并不属于delay(实际上IDeref / IPending)的公共API。
0 投票

在此期间,您可以扩展 clojure.lang.Delaymy.Delay 并重写 isRealized 以取消 同步,并拥有一个新的延迟

(defmacro my-delay [& body]
  (list 'new 'my.Delay (list* `^{:once true} fn* [] body)))
我认为由于 `realized?` 和 `force` 已不再同步,延迟提供的并发原语服务已改变。现在,在作业尚未完成的情况下,多个线程的多个调用者可以同时 `force` 延迟,这意味着在缓存之前thunk可能会被调用多次。
移除 isRealized() 上的 synchronized 并不影响 deref 代码或其在多线程中的语义(deref 仍然在同步中)。

由于 fn 是可变的,此值的发布是安全的,并且将在线程之间看到。
...