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

欢迎!请参阅 关于 页面以了解更多关于这一功能的信息。

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

如果当前正在处理 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/可见的第二个正确/强制?断言。
我认为你所寻找的并不是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` 延迟,这意味着思 sæt 可能将多次调用来缓存之前。
从 isRealized() 移除同步不会更改 deref 代码或其在线程之间的语义(这些线程仍然在 deref() 中同步)。

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