简体   繁体   English

为什么我不能在emacs中的Clojure Cider REPL中从后台线程打印?

[英]Why can't I print from background threads in Clojure Cider REPL in emacs?

If I try to evaluate the following code in my emacs cider-repl, nil is returned, as expected, but none of the printing takes place in the repl buffer or console. 如果我尝试在emacs cider-repl中评估以下代码,则按预期返回nil,但是在repl缓冲区或控制台中都不会进行任何打印。 How can I make this print out as intended? 我怎样才能按预期打印出来?

(dotimes [i 5]                                                                                                                                        
  (.start                                                                                                                                             
   (Thread.                                                                                                                                           
    (fn []                                                                                                                                             
      (Thread/sleep (rand 500))                                                                                                                       
      (println (format "Finished %d on %s" i (Thread/currentThread)))))))
;=> nil

This works fine, however: 但是,这可以正常工作:

(println (format "Finished 1 on %s" (Thread/currentThread)))
;=> Finished 1 on Thread[nREPL-worker-18,5,main]
----------- mini-buffer -----------------
nil

The behavior of println is to use a dynamically bound var called *out* as its output stream. println的行为是使用称为*out*的动态绑定var作为其输出流。 emacs dynamically binds *out* to go to the repl buffer for code evaluated in the repl buffer, but if you create a thread, that thread's *out* gets the root binding of *out* , which in the case of cider will not be the repl buffer. emacs的动态结合*out*去在REPL缓冲区评估代码的REPL缓冲,但是如果你创建一个线程,该线程的*out*获取根的结合*out* ,这在苹果酒的情况下也不会repl缓冲区。

If you started the repl using cider-jack-in , when you look at you buffer list there should be a buffer with a name like *nrepl-server* which contains the output of the root *out* binding. 如果使用cider-jack-in启动repl,则在查看缓冲区列表时,应该有一个名称类似于*nrepl-server*的缓冲区,其中包含根*out*绑定的输出。 Here is the contents of mine after running your code: 这是运行代码后我的内容:

nREPL server started on port 52034 on host 127.0.0.1 - nrepl://127.0.0.1:52034
Finished 1 on Thread[Thread-9,5,main]
Finished 0 on Thread[Thread-8,5,main]
Finished 2 on Thread[Thread-10,5,main]
Finished 3 on Thread[Thread-11,5,main]
Finished 4 on Thread[Thread-12,5,main]

If you did not use cider-jack-in , the output will print to the terminal where you started the nrepl process. 如果您未使用cider-jack-in ,则输出将打印到启动nrepl进程的终端。

*out* is the dynamic variable determining where output from println and similar functions goes. *out*是动态变量,用于确定println和类似函数的输出位置。 It is thread-bound to someplace that causes stuff to be sent back to emacs for display by cider; 它被线程绑定到某个地方,导致东西被苹果酒发送回emacs进行显示。 if you start a new thread, that binding is not present, and the output goes elsewhere (probably to the stdout of the nrepl server emacs/leiningen started in the background). 如果启动新线程,则不存在该绑定,并且输出将移至其他位置(可能到nrepl服务器emacs / leiningen的标准输出在后台启动)。

You can address this in a few ways. 您可以通过几种方式解决此问题。 You could capture the value of *out* from the parent thread, and then pass it along to the child thread in a closure, and rebind *out* to it: 您可以从父线程捕获*out*的值,然后将其传递给闭包中的子线程,然后将*out*重新绑定到它:

(let [out *out*] 
  (.start (Thread. (fn [] 
                     (binding [*out* out]
                        (println "test"))))))

Or you can use a future instead of starting the thread yourself: Clojure automatically conveys relevant thread-local bindings to new threads started for a future. 或者,您可以使用future而不是自己启动线程:Clojure会自动将相关的线程本地绑定传递给为将来启动的新线程。

Execute the following expression in the repl, then all output will end up in the repl: 在repl中执行以下表达式,然后所有输出将最终出现在repl中:

(alter-var-root #'*out* (constantly *out*))

original answer: 原始答案:

https://groups.google.com/d/msg/cider-emacs/bIVBvRnGO-U/nDszDbGoVzgJ https://groups.google.com/d/msg/cider-emacs/bIVBvRnGO-U/nDszDbGoVzgJ

If you are using Figwheel, then doing prn/println in ring handlers (which are actually similar to the Threads example shown above) can also be swallowed by Fighweel itself. 如果您使用的是Figwheel,则在Fig.Weel本身也可以吞咽在环形处理程序中执行prn / println(实际上类似于上面显示的Threads示例)。 Check your project's project.clj (look for the key :server-logfile inside the :figwheel map), where you can control if out should go to the repl or to a logfile. 检查项目的project.clj(查找键:服务器日志文件里面的:figwheel地图),在那里你可以控制,如果应该去REPL或日志文件。 Please note, this only applies if you are using figwheel, otherwise the printing to the REPL of course works fine. 请注意,这仅在您使用花轮时适用,否则当然可以在REPL上进行打印。

See my answer on this question for more details: Output compojure server print statements into figwheel terminal? 有关更多详细信息,请参见我对这个问题的回答:将compojure服务器打印语句输出到figwheel终端?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM