2011-03-22 5 views
5

ExecutorService를 (자바/Clojure의) 내부 스레드를 잠자는 : 그것은 나를 위해 JVM을 사이에 지났는데 나는 기본적으로 여기 궁금내가 스레드 오히려 거대한 수는 Clojure의 프로그램 내에서 생성되는이

(import '(java.util.concurrent Executors)) 
(def *pool* 
    (Executors/newCachedThreadPool)) 

(defn do-something [] 
    ; work 
    Thread/sleep 200 
    ; repeat) 

(dotimes [i 10000] 
    (.submit *pool* do-something)) 

Executor가 실행중인 함수 내에서 sleep 또는 yield 사용에 대한 인수가있는 경우? 이 경우 올바르게 이해하면 모든 직원은 자체 스레드를 가지므로 부작용이 없어야합니다.

집행자는 FixedThreadPool 사용하는 경우 : 자신의 작업이 완료 될 때까지 스레드 풀에 반환되지 않기 때문에

(Executors/newFixedThreadPool 1000) 

일들이 경우 완료하는 데 시간이 오래 걸릴 것입니다 다른 대기중인 근로자를 의미, 더 복잡하게를 스레드가 자고 있습니다.

스레딩에 대한 이해가 정확합니까?

(참고 : 내 디자인은 실제로 잘못 생각하지만, 단지 내가 오른쪽 페이지에 오전 있는지 확인하려면)

답변

7

실행자는 개념적으로 작업 대기열 + 작업자 풀입니다. 여기서 일어날 일에 대한 설명은 기본적으로 정확합니다. 실행 프 N 그 %에 타스크를 제출하면 스레드는 타스크를 실행할 수있을 때까지 대기 행렬에 대기합니다. 작업을 실행할 때 해당 작업은 스레드를 소유하고 잠자기는 다른 작업이 해당 작업자 스레드에서 실행되는 것을 차단합니다.

당신이하고있는 일에 따라 괜찮을 수도 있습니다 (비록 비정상적 일 수도 있고 나쁜 일도있을 수 있습니다). IO를 기다리는 부작용으로 스레드를 차단하는 것이 더 일반적입니다 (예 : 소켓 또는 db 호출에서 차단됨).

일반적으로 정기적 인 작업을 수행하는 경우 풀 외부에서 처리하고 실행해야 할 때 작업하는 것이 더 좋으며, 더 나아가 Executors/newScheduledThreadPool 대신 ScheduledExecutorService을 사용하는 것이 더 좋습니다.

시간 기반 작업을 수행하는 Java의 다른 주요 메커니즘은 java.util.Timer입니다.이 기능은 사용하기가 조금 쉽지만 ScheduledExecutorService만큼 강력하지는 않습니다.

Clojure의 또 다른 대안은 명시 적으로 대신 당신에 의해 Clojure를 관리하는 백그라운드 스레드로 작업자를 배치하는 것입니다

:

(defn do-task [] 
    (println (java.util.Date.) "doing task")) 

(defn worker [f n wait] 
      (doseq [task (repeat n f)] 
        (f) 
        (Thread/sleep wait))) 

;; use future to execute worker in a background thread managed by Clojure 
(future (worker do-task 10 1000)) 

;; the call to future returns immediately but in the background console 
;; you will see the tasks being run. 
-1

이 스레드를 수면에 대한 대안은 각 노동자를하는 것입니다 가지고 "sleepUntil"long 값 . 유언 집행자가 근로자에게 전화를하는 경우, 집에 있으면 즉시 반환됩니다. 그렇지 않으면 작업을 수행 한 다음 반환합니다. FixedThreadPoolExecutor는 스레드가있는 것보다 많은 수의 작업자를 처리 할 수 ​​있기 때문에 스레드 수를 줄이는 데 도움이됩니다. 대부분 스레드가 수면으로 플래그가 지정되고 빠르게 반환되는 경우입니다.