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

欢迎!请参阅 关于 页面了解有关此页面的更多信息。

+5 投票
命名空间和变量
重新分类

你好!我一直在 future 中使用 clojure.tools.build.api 的一些函数,并经常看到以下错误...

Execution error (IllegalStateException) at clojure.tools.build.api/create-basis (api.clj:154).
Attempting to call unbound fn: #'clojure.tools.build.tasks.create-basis/create-basis

从 tools.build 执行...

(defn create-basis
  ([]
   ((requiring-resolve 'clojure.tools.build.tasks.create-basis/create-basis)))
  ([params]
   ((requiring-resolve 'clojure.tools.build.tasks.create-basis/create-basis) params)))

...代码实际上仅使用 requiring-resolve 来执行另一个函数。进一步研究 requiring-resolve,我可以看到第一个对 resolve 的调用并没有与 serialized-require 函数使用的相同锁同步...

(defn- serialized-require
  [& args]
  (locking clojure.lang.RT/REQUIRE_LOCK
    (apply require args)))

(defn requiring-resolve
  [sym]
  (if (qualified-symbol? sym)
    (or (resolve sym)
        (do (-> sym namespace symbol serialized-require)
            (resolve sym)))
    (throw (IllegalArgumentException. (str "Not a qualified symbol: " sym)))))

第一个问题是,当另一个线程通过 serialized-require 正在 requiring 该命名空间时,requiring-resolve 是否有可能从第一个 resolve 调用返回 clojure.lang.Var$Unbound?假设是这样,tools.build(我认为扩展到大多数 Clojure 代码)应该避免使用 ((requiring-resolve 'some-other/function)) 模式吗?requiring-resolve 是否可以修改为线程安全?

谢谢!

1 答案

0 投票

《requiring-resolve》的目的是线程安全的,所以如果有什么问题,这应该被视为是Clojure的问题。实际上,《requiring-resolve》是使《require》本身线程安全的一个中间阶段,这是一个更大、更复杂的问题(示例报告在https://clojure.atlassian.net/browse/CLJ-1876)。这个问题的影响非常深远,最终与命名空间不可变(我们本应该知道这一点!)有关。

无论如何,我已经在这里进行了报告

https://clojure.atlassian.net/browse/CLJ-2735

...