使Clojure的println为“线程安全".与Java中的方式相同 [英] Make Clojure's println "thread-safe" in the same way as in Java

查看:73
本文介绍了使Clojure的println为“线程安全".与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:

  1. println 函数是多个Arity.如果交给多个对象,它将对 * out * 进行多次写入.
  2. println 的调用被委派给一个称为 print-method 的内部多重方法(可以扩展为添加对自定义类型的打印支持).非字符串对象(尤其是集合类型)的 print-method 实现可以对 * out * 进行多次写入.这与Java的 println 相对,后者将在对象上调用 .toString 并进行一次写入.
  1. The println function is multiple arity. If handed multiple objects, it makes multiple writes to *out*.
  2. Calls to println are delegated to an internal multimethod called print-method (which can be extended to add print support for custom types). The print-method implementation for non-string objects, especially collection types, can make multiple writes to *out*. This is in contrast to Java's println 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆