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

欢迎!有关如何工作的更多信息,请参阅关于页面。

+4
引用,代理,原子
已关闭

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

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

(此外,似乎没有与并发编程相关的任何标签或类别,但鉴于延迟是clojure.core的一部分,我假设这是正确的提问位置)

带有备注“已修复在1.11.0-alpha2”关闭

2 个答案

+1
感谢你这么快就解决这个问题,Alex。

昨天我还注意到,试图在不解引用的情况下在REPL中打印执行延迟的值也会阻塞。然而,我99%确信那只是因为构建字符串表示形式的那个东西也在调用"realized?",所以我认为这不是一个不同的错误。
根据realized?的docstring,我同意在延迟当前正在进行的条件下返回false是正确的行为。尽管如此,确实有在这种情况下,我会在并发上下文中使用延迟和realized?来知道“延迟是否已被强制执行?”,以决定是否要在原子中替换延迟(或等待正在执行的过程完成)。我可以使用deref来实现这一点,除了我不想在没有已开始执行的情况下启动该过程。

如果我对1.11的正确理解不再可以使用realized?来检测这种情况。有没有一种官方的方式来回答“延迟是否已被强制执行?”或者我现在需要创建自己的构造函数?

一个成为true的isForced() / forced?谓词,在一个线程进入deref中的同步块后(但在thunk开始/完成后)对其他线程可见,这可能是解决我所提问题的其中一个方案。
我想你想要的东西不是delay(实际上是IDeref / IPending)的公共API的一部分。
0

同时,您可以扩展 clojure.lang.Delaymy.Delay 并重写 isRealized 使其不带 synchronized,从而创建新的延迟

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

因为 fn 是 volatile 的,所以这个值的安全发布会在线程之间可见。
...