首页 > 解决方案 > Clojure 使用零个或一个输入的函数运行多个线程

问题描述

我正在 Clojure 中尝试运行独立线程,但我得到了我不理解的不同行为。

对于我的代码编辑器,我使用的是 Atom(不是 emacs),REPL 是 Chlorine。

我正在测试一个非常简单的函数,它只打印数字。这个从 100 打印到 1 并且不接受任何输入:

(defn pl100 []
  "pl100 = Print Loop from 100 to 1"
  (loop [counter 100]
    (when (pos? counter)
      (do
        (Thread/sleep 100)
        (println (str "counter: " counter))
        (recur (dec counter))))))

这个做完全相同的事情,除了它需要一个输入:

(defn pl-n [n]
    "pl-n = Print Loop from n to 1"
    (loop [counter n]
      (when (pos? counter)
        (do
          (Thread/sleep 100)
          (println (str "counter: " counter))
          (recur (dec counter))))))

当我使用

(.start (Thread. #(.run pl100)))
; --> prints to console REPL
; --> runs with no errors

这段代码

  1. 打印到控制台 REPL(我称之为 lein)和
  2. 运行没有错误

当我使用

(.start (Thread. #(.run (pl-n 100))))
; prints to console REPL
; --> java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "target" is null

这段代码

  1. 打印到控制台 REPL
  2. 以上述异常结束

当我使用

(.start (Thread. pl100))
; --> prints to the console REPL
; --> runs with no errors  

这段代码

  1. 打印到控制台 REPL
  2. 运行没有错误

当我使用

(.start (Thread. (pl-n 100)))
; --> prints to Atom REPL, not console REPL!
; ends with exception 
; Execution error (NullPointerException) at java.lang.Thread/<init> (Thread.java:396).
; name cannot be null
; class java.lang.NullPointerException

这段代码

  1. 打印到 Atom REPL(我使用的是 Atom,而不是 emacs)!不像其他人那样去控制台 REPL
  2. 以异常结束

所以,有人可以帮我理解:

  1. 为什么当我运行一个需要输入的函数时,Java 会出错?为什么函数调用不等价?
  2. (.run ...) 在做什么?
  3. 为什么有时代码会打印到控制台,而有时会打印到 Atom/Chlorine?

标签: multithreadingconcurrencyclojure

解决方案


简而言之: Thread.run需要一个功能。你的第一个展览给了它一个功能,pl100,并按你期望的那样工作:

#(.run pl100)

.run如果你给出的不是函数,而是调用函数返回的值,那么会发生完全不同的事情pl100。事实上,pl100返回 nil,所以Thread.run会抛出 NullPointerException:

#(.run (pl100)) ;; NullPointerException

这就解释了为什么你的第二个展览没有达到你的预期。 pl-n返回 nil,然后当您将 nil 传递给时出现异常Thread.run

#(.run (pl-n 100)) ;; NullPointerException

为了弥合差距 -Thread.run需要无参数的函数和pl-n需要参数的函数,您可以引入一个无参数的函数(以满足Thread.run),它pl-n使用所需的参数调用。习惯上这将是一个匿名函数。不幸的是,您不能嵌套#()在其中#(),因此您必须(fn [] ...)对其中一个匿名函数使用更冗长的语法,很可能是外部函数。


推荐阅读