使Clojure的println为“线程安全".与Java中的方式相同 [英] Make Clojure's println "thread-safe" in the same way as in Java
问题描述
在Clojure中并发调用 println
的同时,我发现它的行为不同于Java的 System.out.println
.
While playing around with concurrent calls to println
in Clojure I found that its behaviour is different from Java's System.out.println
.
我会用Java写什么
class Pcalls {
public static void main(String[] args) {
Runnable[] fns = new Runnable[3];
for (int i = 0; i < 3; i++) {
fns[i] = new Runnable() {
@Override public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Hello iteration " + i);
}
}
};
}
for (Runnable fn : fns) new Thread(fn).start();
}
}
我在Clojure中解释为:
I paraphrased in Clojure as:
(doall (apply pcalls
(repeat 3 #(dotimes [i 5] (println "Hello iteration" (inc i))))))
不幸的是,在Clojure版本中,输出行通常看起来是交错的:
Unfortunately, in the Clojure version the output lines often appear interleaved:
Hello iterationHello iteration 1
Hello iteration Hello iteration 2
Hello iteration 3
1
Hello iteration 4
1
Hello iteration Hello iteration5
Hello iteration 2
Hello iteration 23
Hello iteration Hello iteration 4
3Hello iteration
5
Hello iteration 4
Hello iteration 5
(nil nil nil)
在Java中,这永远不会发生,每条消息都打印在自己的行上.
In Java this never happens, every message is printed on its own line.
您能解释一下Clojure的 println
与Java为何以及为何不同,以及如何在Clojure中使用 println
达到类似的线程安全"行为吗?/p>
Can you explain how and why Clojure's println
differs from Java's, and how to arrive at a similar kind of "thread-safe" behaviour with println
in Clojure?
推荐答案
在内部, println
将输出发送到writer,该输出是 * out *
当前绑定的值.有几个原因导致对此调用不是原子的:
Internally, println
sends output to the writer that is the currently-bound value for *out*
. There are a couple of reasons that calls to this are not atomic:
-
println
函数是多个Arity.如果交给多个对象,它将对* out *
进行多次写入. - 对
println
的调用被委派给一个称为print-method
的内部多重方法(可以扩展为添加对自定义类型的打印支持).非字符串对象(尤其是集合类型)的print-method
实现可以对* out *
进行多次写入.这与Java的println
相对,后者将在对象上调用.toString
并进行一次写入.
- The
println
function is multiple arity. If handed multiple objects, it makes multiple writes to*out*
. - Calls to
println
are delegated to an internal multimethod calledprint-method
(which can be extended to add print support for custom types). Theprint-method
implementation for non-string objects, especially collection types, can make multiple writes to*out*
. This is in contrast to Java'sprintln
which will call.toString
on the object and make a single write.
如果要使用原子println,则可能必须显式同步您的调用,例如:
If you want atomic println's, you'll probably have to explicitly synchronize your calls, e.g.:
(let [lock (Object.)]
(defn sync-println [& args]
(locking lock (apply println args))))
这篇关于使Clojure的println为“线程安全".与Java中的方式相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!