2024 Clojure 调查问卷!中分享您的想法。

欢迎!请参阅“关于”页面以获取更多如何使用本站的信息。

+4
引用、代理、原语
已关闭

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

我原本期望的行为是它应该返回false,这与未来的行为相同。毕竟,如果您想等待它完成,您会使用deref

(此外,似乎没有与并发编程相关的标签或分类,但由于延时是clojure.core的一部分,我假设这是提问的正确地方)

在备注“修复在1.11.0-alpha2”中关闭

2 个答案

+1
感谢你如此迅速地回应这个问题,Alex。

昨天我也注意到,如果在REPL中尝试打印执行延迟的值而不解除引用它也会阻塞。然而,我99%确信这只是因为构建字符串表示形式的任何东西也在调用"realized?",所以我认为这不是一个不同的错误。

编辑了
根据 realized? 的文档,我同意如果在执行中延迟,则返回 false 是正确的行为。但这确实有一些时候,我会在并发环境中使用延迟和 realized? 来确定“延迟是否已被强制?”以决定我是否要在原子操作中替换延迟或等待已启动的流程完成。我可以使用 deref 来这样做,除了我不希望在它未启动的情况下启动流程。

如果我的理解正确,在1.11之后,我不能再使用 realized? 来检测这种案例。是否有支持的方式来回答“延迟是否已被强制?”或者我现在需要创建自己的结构?

一个成为真正的 isForced() / forced? 断言的二进制实例,一旦进入 deref 中的同步块(但在 thunk 开始/完成之前)成为真正的/可看到的,这是一个可能的解决方案,用以解答我所询问的。
我认为你正在寻找的并不是 delay(实际上是 IDeref / IPending)的公共接口的一部分。
0

在此期间,您可以将clojure.lang.Delay扩展为my.Delay,并覆盖isRealized使其不同步,并创建一个新的延迟

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

因为fn是volatile的,此值的发布是安全的,并且将在跨线程中看到。
...