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

发布于 2024-10-09 08:34:42 字数 638 浏览 3 评论 0原文

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

编辑:感谢 Daniel 在下面的回答,我现在知道其他线程没有 out 绑定到 REPL 的输出。此代码之所以有效,是因为您从运行位置传入out。然而我的新问题是,这段代码现在会阻塞每个线程,因此它不是并行运行,而是一次运行每个线程,所以我需要一种更多线程感知的输出方法。

(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)))))))

When I run Clojure code from the Swank repl in emacs, the main thread will print out messages using printf to the repl. But if I run agents or explicitly create other threads which also print, sometimes the output doesn't show up, and other times it shows up in the console window where I'm running Swank. I'd love to understand why.

Edit: Thanks to Daniel's answer below I now know that the other threads do not have out bound to the output of the REPL. This code works because you pass in the out from where you run from. However my new problem is that this code now blocks per thread so rather than running in parallel it runs each thread one at a time, so I need a more thread aware output method.

(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)))))))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

萧瑟寒风 2024-10-16 08:34:42

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

(let [repl-out *out*]
  (defn foo []
    (binding [*out* repl-out]
      ...)))

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

或者,用于测试:

(defmacro future-output [& body]
  `(let [out# *out*]
     (future
       (binding [*out* out#]
         ~@body))))

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

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

The reason is, that in other threads *out* is not bound to the REPL's stream. Try something like this:

(let [repl-out *out*]
  (defn foo []
    (binding [*out* repl-out]
      ...)))

Now, when running foo from another thread, *out* will be bound to whatever it was when you defined the function (i.e. the SLIME REPL), so printing will work as expected.

Or, for testing:

(defmacro future-output [& body]
  `(let [out# *out*]
     (future
       (binding [*out* out#]
         ~@body))))

Note: This is untested, because I have no working Clojure/SLIME here atm, but that code worked a few months ago. There might be differences in newer Versions of Clojure (1.3 Alpha 2):

  • code path for using vars is now
    much faster for the common case,
    and you must explicitly ask for :dynamic bindability
冰魂雪魄 2024-10-16 08:34:42

如果您在使用 cake 时遇到同样的问题,则项目根目录(project.clj 所在的位置)中的 .cake/cake.log 文件中应该有一个包含输出的日志文件。

If you are struggling with the same using cake, there should be a log file with the output in the .cake/cake.log file in your project root (where project.clj lives).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文