2011-11-08 5 views
4

의 조이 Clojure의 Fogus의 책을 읽고 병렬 프로그래밍 장에서 중요한 것을 분명히 보여주고 싶지만 무엇을 찾을 수없는 함수 정의를 보았습니다. 또한, 나는이 기능이 무엇인지 볼 수 없습니다 - 내가 실행할 때, 그것은 아무것도하지 않습니다 :이 방법으로 실행하려고Clojure dothreads! 함수

(import '(java.util.concurrent Executors)) 
    (def *pool* (Executors/newFixedThreadPool 
    (+ 2 (.availableProcessors (Runtime/getRuntime))))) 

(defn dothreads! [f & {thread-count :threads 
         exec-count :times 
         :or {thread-count 1 exec-count 1}}] 
    (dotimes [t thread-count] 
    (.submit *pool* #(dotimes [_ exec-count] (f))))) 

:

(defn wait [] (Thread/sleep 1000)) 
(dothreads! wait :thread-count 10 :exec-count 10) 
(dothreads! wait) 
(dothreads! #(println "running")) 

이 ...하지만 그것은 nil을 반환합니다. 왜?

답변

6

여기에 동일한 코드가 있습니다.이 코드는 약간 변경되어 dothreads!에 전달 된 함수가 내부의 수인 dotimes을 전달합니다.

(import 'java.util.concurrent.Executors) 

(def ^:dynamic *pool* (Executors/newFixedThreadPool (+ 2 (.availableProcessors (Runtime/getRuntime))))) 

(defn dothreads! [f & {thread-count :threads 
         exec-count :times 
         :or {thread-count 1 exec-count 1}}] 
    (dotimes [t thread-count] 
    (.submit *pool* #(dotimes [c exec-count] (f c))))) 

(defn hello [name] 
    (println "Hello " name)) 

이처럼 실행 해보십시오 : 나를 위해

(dothreads! hello :threads 2 :times 4) 

, 그것의 효과에 뭔가를 인쇄 : 그래서, 함수를 호출 할 때 당신이 만든 하나의 실수를주의

Hello 0 
Hello 1 
Hello 2 
Hello 3 
nil 
user=> Hello 0 
Hello 1 
Hello 2 
Hello 3 

: : thread-count: exec-count은 키로 사용되었지만 실제로는 t의 바인딩입니다. 그는 dothreads! 내부에서 일어나고있다. 키워드는 콜론 (:)으로 시작하는 단어입니다 (:threads:times). 이 코드는 실제로 무엇을하는지에 관해서는

:

  1. 그것은 당신의 컴퓨터 + 2 대부분에 코어의 번호를 사용하는 새로운 고정 크기의 스레드 풀을 만듭니다. 이 풀은 *pool*이라고하며 Java Executor Framework을 사용하여 만듭니다. 자세한 내용은 [1]을 참조하십시오.

  2. dothreads! 기능은 thread-count 각 스레드에 exec-count 번 호출되는 함수를 가져옵니다. 위의 예제에서 스레드 당 4 번 호출되는 것을 명확하게 볼 수 있습니다 (:threads이 2이고 :times이 4 임).

  3. 이 함수가 nil을 반환하는 이유는 dothreads!이 아무 것도 반환하지 않기 때문입니다.스레드 풀의 submit 메서드는 Java에서 void를 반환하므로 Clojure에서 nil을 반환합니다. 당신이 그것을 만드는 함수의 끝에서 다른 표현을 추가한다면 :

    (defn dothreads! [f & {thread-count :threads 
             exec-count :times 
             :or {thread-count 1 exec-count 1}}] 
        (dotimes [t thread-count] 
        (.submit *pool* #(dotimes [c exec-count] (f c)))) 
        (* thread-count exec-count)) 
    

그것은 위의 예를 들어 8을 반환합니다 (2 * 4). 함수의 마지막 표현식 만 반환되므로 함수에서 (fn [x y] (+ x y) (* x y))을 작성하면 항상이 함수가 반환됩니다. 합계가 계산되지만 은 0이됩니다. 그러니하지 마! 함수에 하나 이상의 표현식을 추가하려면 마지막 표현식을 제외한 모든 표현식에 부작용이 있는지 확인하십시오. 그렇지 않으면 쓸모가 없습니다.

  1. 인쇄 된 순서가 비동기임을 알 수 있습니다. 그래서, 내 컴퓨터에서 4 번 안녕하세요, 다음 함수의 결과를 반환하고 4 번만 인사. 함수가 실행되는 순서는 스레드 사이에서 결정되지 않지만 hello는 각 스레드에서 순차적입니다 (Hello 2 전에는 Hello 3이 될 수 없습니다). 순차성 이유는 실제로 스레드 풀에 제출 함수가 #(dotimes [c exec-count] (f c))

[1] 좋아 http://download.oracle.com/javase/tutorial/essential/concurrency/executors.html

+0

이 설명을 가져 주셔서 감사합니다! 사실, 나는 당신의 코드를 가지고 놀았습니다. 처음에는 cljr에서 아무 것도 출력하지 못했습니다 : [link] (http://i44.tinypic.com/11io8pl.png) 하지만 이상하게도 - 명령 프롬프트에서 cljr을 실행하면 (cmd) Windows에서, 그것은 바로 cmd 창에 메시지를 출력합니다! 그런 다음 익명 함수로 모든 것을 시도했습니다. (dothreads! (println "Hello"name) : threads 2 : times 4) ... 그러나 이상하게도 작동하지 않았습니다. – asdfghjkl

+0

아마도 "cljr-without-cmd"모드에서 인쇄물이 부족한 이유는 println 함수가 "System.out.println"호출을 Java (?) 호출로 컴파일했기 때문입니다.이 호출은 올바른 인쇄를 원합니다. 일부 콘솔 출력 (?). 기본적으로 cljr은 소스 코드를 평가하는 동안 println을 "catch"하지만 print를 실행하는 다른 Java 스레드가 출력을 작성할 위치를 알지 못합니다 ... 그러나 이것은 추측입니다. – asdfghjkl

+0

지금 당장 추측하십시오.하지만 Clojure 1.3을 사용하여 코드를 실행 해보십시오. 그게 내가 그것을 테스트 한 것입니다. 왜 당신의 예제에서 아무 것도 출력하지 못했습니다. Err, 내 대답을 수락하면, 또한 체크하십시오;) –

3

나중에 책에서 테스트 함수를 여러 스레드에서 여러 번 실행하는 데 사용됩니다. 그것은 그 자체로 아무것도 설명하지 않지만, 잠금, 약속 및 기타 병렬 및 동시 작업을 설명하는 데 사용됩니다.

+0

, 내가 읽어 것이다 것입니다! – asdfghjkl

1

dotimes, dothreads!println은 부작용을 유발하는 데 사용됩니다. 예 :

user=> (println 3) 
3 
nil 

코드 스 니펫은 3을 화면에 인쇄하지만 nil을 반환합니다. 마찬가지로 dothreads!은 부작용이 있으며 반환 값이 아닙니다.