使用swank/slime了解Clojure中的输出

jus*_*nhj 6 printf multithreading clojure slime

当我在emacs中从Swank repl运行Clojure代码时,主线程将使用printf将消息打印到repl.但是如果我运行代理或显式创建其他也打印的线程,有时输出不会显示,有时它会显示在我运行Swank的控制台窗口中.我很想知道为什么.

编辑:感谢丹尼尔的回答下面我现在知道了其他线程不必绑定到REPL的输出.此代码有效,因为您从运行的位置传出.但是我的新问题是这个代码现在阻塞每个线程,所以不是并行运行,而是每次运行一个线程,所以我需要一个更多线程感知的输出方法.

(defn sleeper-thread [out id t]
  "Sleep for time T ms"
  (binding [*out* out]
    (printf "%d sleeping for time %d\n" id t)
    (Thread/sleep t)
    (printf "%d slept\n" id)))

(defn test-threads [n out]
  (dotimes [x n]
    (.start (Thread. (#(sleeper-thread %1 %2 %3) out x (+ 2000 (rand-int 5000)))))))
Run Code Online (Sandbox Code Playgroud)

dan*_*lei 1

原因是,在其他线程中*out*没有绑定到 REPL 的流。尝试这样的事情:

(let [repl-out *out*]
  (defn foo []
    (binding [*out* repl-out]
      ...)))
Run Code Online (Sandbox Code Playgroud)

现在,当foo从另一个线程运行时,*out*将绑定到定义函数时的任何内容(即 SLIME REPL),因此打印将按预期工作。

或者,为了测试:

(defmacro future-output [& body]
  `(let [out# *out*]
     (future
       (binding [*out* out#]
         ~@body))))
Run Code Online (Sandbox Code Playgroud)

注意:这是未经测试的,因为我这里没有可用的 Clojure/SLIME,但该代码在几个月前就可以工作。新版本的 Clojure (1.3 Alpha 2)可能存在差异:

  • 对于常见情况,使用 vars 的代码路径现在要 快得多,并且您必须明确要求 :dynamic 可绑定性