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

欢迎!有关更多信息,请参阅关于页面。

+4
Clojure

作为Apache Storm的一部分,我们有一些代码可以从Java中使用以下代码加载Clojure函数。

`

public static IFn loadClojureFn(String namespace, String name) {
    try {
        clojure.lang.Compiler.eval(RT.readString("(require '" + namespace + ")"));
    } catch (Exception e) {
        //if playing from the repl and defining functions, file won't exist
    }
    return (IFn) RT.var(namespace, name).deref();
}

`

如果这个函数同时从多个不同的线程中调用,尝试导入相同的命名空间,我偶尔会得到一些非常奇怪的错误。注:我不得不修改catch以真正打印出它得到的错误消息(我们也不应该吃掉异常)。

{verbatim}
2016-01-07 16:26:09.305 b.s.u.Utils (link: WARN) 加载命名空间失败
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: 无法在当前上下文中解析符号:sentence-spout,编译:(storm/starter/clj/word_count.clj:21:1)

at clojure.lang.Compiler.analyze(Compiler.java:6543) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.analyze(Compiler.java:6485) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3791) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:6725) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.analyze(Compiler.java:6524) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.analyze(Compiler.java:6485) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.eval(Compiler.java:6786) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.load(Compiler.java:7227) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RT.loadResourceScript(RT.java:371) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RT.loadResourceScript(RT.java:362) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RT.load(RT.java:446) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RT.load(RT.java:412) ~(link: clojure-1.7.0.jar:?)
at clojure.core$load$fn__5448.invoke(core.clj:5866) ~(link: clojure-1.7.0.jar:?)
at clojure.core$load.doInvoke(core.clj:5865) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RestFn.invoke(RestFn.java:408) ~(link: clojure-1.7.0.jar:?)
at clojure.core$load_one.invoke(core.clj:5671) ~(link: clojure-1.7.0.jar:?)
at clojure.core$load_lib$fn__5397.invoke(core.clj:5711) ~(link: clojure-1.7.0.jar:?)
at clojure.core$load_lib.doInvoke(core.clj:5710) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RestFn.applyTo(RestFn.java:142) ~(link: clojure-1.7.0.jar:?)
at clojure.core$apply.invoke(core.clj:632) ~(link: clojure-1.7.0.jar:?)
at clojure.core$load_libs.doInvoke(core.clj:5749) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RestFn.applyTo(RestFn.java:137) ~(link: clojure-1.7.0.jar:?)
at clojure.core$apply.invoke(core.clj:632) ~(link: clojure-1.7.0.jar:?)
at clojure.core$require.doInvoke(core.clj:5832) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.RestFn.invoke(RestFn.java:408) ~(link: clojure-1.7.0.jar:?)
at clojure.core$eval114.invoke(NO_SOURCE_FILE:0) ~(link: ?:?)
at clojure.lang.Compiler.eval(Compiler.java:6782) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.eval(Compiler.java:6745) ~(link: clojure-1.7.0.jar:?)
at backtype.storm.utils.Utils.loadClojureFn(Utils.java:602) (link: storm-core-0.11.0-SNAPSHOT.jar:0.11.0-SNAPSHOT)
at backtype.storm.clojure.ClojureBolt.prepare(ClojureBolt.java:57) (link: storm-core-0.11.0-SNAPSHOT.jar:0.11.0-SNAPSHOT)
at backtype.storm.daemon.executor$fn__8297$fn__8310.invoke(executor.clj:785) (link: storm-core-0.11.0-SNAPSHOT.jar:0.11.0-SNAPSHOT)
at backtype.storm.util$async_loop$fn__556.invoke(util.clj:482) (link: storm-core-0.11.0-SNAPSHOT.jar:0.11.0-SNAPSHOT)
at clojure.lang.AFn.run(AFn.java:22) (link: clojure-1.7.0.jar:?)
at java.lang.Thread.run(Thread.java:745) (link: ?:1.8.0_60)

原因:java.lang.RuntimeException: 无法在当前上下文中解析符号:sentence-spout

at clojure.lang.Util.runtimeException(Util.java:221) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.resolveIn(Compiler.java:7019) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.resolve(Compiler.java:6963) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6924) ~(link: clojure-1.7.0.jar:?)
at clojure.lang.Compiler.analyze(Compiler.java:6506) ~(link: clojure-1.7.0.jar:?)
... 33 more

{verbatim}

如果我将静态Java函数设置为synchronized,问题就会消失。它总是在解析一些特定的宏时崩溃,此时它会混淆某个特定的符号无法解析。

正在尝试加载的命名空间。
https://github.com/apache/storm/blob/a99d9c11be005ade7c308bebdda71c7fb0111acc/examples/storm-starter/src/clj/storm/starter/clj/word_count.clj

似乎会引发异常的宏。
https://github.com/apache/storm/blob/a99d9c11be005ade7c308bebdda71c7fb0111acc/storm-core/src/clj/backtype/storm/clojure.clj#L77-L138

如我所说,这看起来像是一种某种类型的线程问题。当我添加了synchronized关键字后,一切都正常工作。

4 个答案

0

评论由:hiredman发表

从Clojure调用require也不是线程安全的,这与这个没有区别

0

评论由:jafingerhut 发布

这个问题可能通过使用最新版 Clojure 1.10 中添加的 serialized-require 来解决吗?

0

评论由:alexmiller 发布

计划在未来的版本中对 require 进行重构,以不再需要 serialized-require。可能的方式是那样的,也可能有其他的方式。这个问题基本上就是实际工作的占位符。在 serialized-require 中添加锁是一个很大的锤子,我们希望让它更加精细。

提问 2020年11月28日 Clojure require 不是线程安全的
0
参考: https://clojure.atlassian.net/browse/CLJ-1876(由 alex+import 报告)
...