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

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

+5
in Namespaces and vars by
recategorized by

你好!我一直在一个 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-resolve 是否实际上在第一次调用 resolve 时返回 clojure.lang.Var$Unbound?假设如此,那么 tools.build(以及我想扩展到大多数 Clojure 代码)应避免使用 ((requiring-resolve 'some-other/function)) 模式?requiring-resolve 是否可以被修改为线程安全?

谢谢!

1 答案

0
by

requiring-resolve的目的是线程安全的,实际上,这应该是Clojure的一个问题。实际上,requiring-resolve是使require本身线程安全的一个折中的方法,这是一个更大、更复杂的问题(示例报告见https://clojure.atlassian.net/browse/CLJ-1876)。这个问题的根源相当深,最终与名称空间不是不可变有关(我们应该是知道的!)。

无论如何,我已经在这里提出

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

...