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

欢迎!请参阅 关于 页面以了解更多关于如何进行操作的详细信息。

+6
Clojure

我们现在遇到了这个问题相当频繁,因为我们重用了大量使用 Clojure 的系统,我想数字确实是在 与我们作对,但无论如何,这阻碍了 Clojure 在多线程环境中的应用。我已经准备了一个 最小化示例 以重现该问题。所以问题是,

  • 有什么方法可以解决这个问题?(类似于我们设置的某些动态 var,我没有找到,但可能会有)
  • 为什么这被认为是“重型锤子”?(例如,require 很少使用,通常在单线程环境(如 repl)中,而大多数生产环境都将从中受益)
  • 有什么线索解释为什么会发生这种情况?(阅读源代码,我并不完全理解为什么会发生这种情况,可能是因为一些 ns requires(添加 ns)并因此添加所有符号时,另一个线程在 require 时替换了那个 ns)

1 答案

+2

存在一个私有的函数 serialized-require,它在进行require之前简单地获取一个全局锁,你可以使用它,或者在Java代码中围绕任何使用clojure.core/require的地方做同样的事情,即通过获取全局锁来包装它,例如通过在单个对象上调用一个同步方法内的所有require调用。

感谢您的回答,我知道这一点,然而这在我们的情况下是不行的:“:”(),因为至少有一个这些类是AOT编译的,它反过来使用`loadWithClass`,这又反过来调用`require`(用于加载`clj`文件),而我们无法控制。
如果你无法更改那个AOT编译的代码,因为这确实不在你的控制之下,你能否评价以下代码,并确保它在从多个线程调用`require`之前在系统启动时被评价?当然,println是可选的。


(def original-require clojure.core/require)

(defn my-serialized-require [& args]
  (locking clojure.lang.RT/REQUIRE_LOCK
    (println "my-serialized-require 获取了锁...")
    (apply original-require args)
    (println "my-serialized-require 释放锁...")))

(alter-var-root #'clojure.core/require (fn [& args] my-serialized-require))


如果不能为你做到这一点,你能否编译Clojure源代码的修改版本并在你的项目中使用它?如果可以,你可以在某种程度上修改`require`的定义,使其变为带有锁的版本。
至于其价值,require-resolve是线程安全(锁定)require的公共API,我的理解是,计划有一天(也许在Clojure 1.11?Alex可能在这方面有一些见解)使用此机制将普通的require改为线程安全的,但在将此类更改应用于Clojure的基本组成部分之前,还需要进行一些分析和可能的研究。
再次感谢,现在我明白问题所在,我认为我们可以为我们的情况放置一个解决方案,然而,这并没有解决根本问题,我非常希望能看到对这一问题的长期、通用的解决方案。
再次感谢,现在我明白问题所在,我认为我们可以为我们的情况放置一个解决方案,然而,这并没有解决根本问题,我非常希望能看到对这一问题的长期、通用的解决方案。
我理解你对于长期通用解决方案的需求。我是一个感兴趣的志愿者,针对你要求解决方案的一部分进行了回应。我没有控制Clojure发布版内容的权力。Clojure的官方维护者也阅读这些问题,并且他们会给出他们认为的长期通用解决方案。
非常感谢你的理解和帮助!
你好,刚刚回声了上面的事情——是的,这是一个已知的问题,目前已被列入Clojure 1.11的候选列表中。并行(冲突)加载相对较少。`requiring-resolve`是在1.10版本中加入的,用以覆盖最常见的动态加载使用场景(这可能很容易发生竞争)。

正如Andy上面提到的,`clojure.lang.RT/REQUIRE_LOCK`故意被留下,以便需要参与此锁的用户程序可以做到。这仍然应被视为实现细节,并可能在未来被移除,但在此期间,可以像你所提到的那样使用建议的解决方案。

预期长期解决方案是使正常的`require`更安全,但这需要完成大量分析和测试,目前尚未完成。
by
`gen-class`可能也是一个常见的使用场景。如果你从Clojure生成一个类,并且Java在多个线程中创建该类的实例,所生成的类初始化器很可能会不安全地以非线程安全的方式在底层调用实现Clojure命名空间的代码。我们目前似乎存在这个问题。
...