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

欢迎!请查看关于页面以获取更多关于如何使用此页面的信息。

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

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

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

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

附带以下备注关闭: 已修复在 1.11.0-alpha2 中

2 个答案

+1
亚历克斯,非常感谢你能这么快处理这个问题。

昨天我还留意到,在REPL中尝试打印执行延迟的值而不进行解引用也会阻塞。但是,我有99%的把握认为这只是因为构建字符串表示形式的任何东西也在调用“realized?”,所以我认为这不是一个问题。

编辑
考虑到 realized? 的文档字符串,我同意如果在执行中的延迟,则返回 false 是正确的行为。但是,肯定有情况是,我在并发上下文中同时使用延迟和 realized? 来确定“延迟是否已被强制执行?”以决定是否在原子中替换延迟(或等待已经执行的进程完成)。对于这个目的,我可以使用解引用除外,我不想在没有执行的进程的情况下启动该进程。

如果我理解正确,在 1.11 版本之后,我不能再使用 realized? 来检测这种情况。是否有支持判断“延迟是否已被强制执行?”的方法,或者我现在需要为自己的结构创建方法?

一个 forcer() / forced? 变量可以作为一个可能的解决方案,它在 deref 的同步块进入时(在 thouck 开始/完成后)变为真/对所有线程可见。
我认为你想要的东西不是 delay(实际上是 IDeref / IPending)的公用 API 的一部分。
0 投票

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

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

因为 fn 是 volatile 的,这个值的发布是安全的,并且将在所有线程中可见。
...