2011-02-16 4 views

답변

18

당신은 참조하십시오

> (use 'clojure.repl) 
> (source pmap) 
(defn pmap 
    "Like map, except f is applied in parallel. Semi-lazy in that the 
    parallel computation stays ahead of the consumption, but doesn't 
    realize the entire result unless required. Only useful for 
    computationally intensive functions where the time of f dominates 
    the coordination overhead." 
    {:added "1.0"} 
    ([f coll] 
    (let [n (+ 2 (.. Runtime getRuntime availableProcessors)) 
     rets (map #(future (f %)) coll) 
     step (fn step [[x & xs :as vs] fs] 
       (lazy-seq 
       (if-let [s (seq fs)] 
        (cons (deref x) (step xs (rest s))) 
        (map deref vs))))] 
    (step rets (drop n rets)))) 
    ([f coll & colls] 
    (let [step (fn step [cs] 
       (lazy-seq 
       (let [ss (map seq cs)] 
        (when (every? identity ss) 
        (cons (map first ss) (step (map rest ss)))))))] 
    (pmap #(apply f %) (step (cons coll colls)))))) 

(+ 2 (.. Runtime getRuntime availableProcessors))가 큰 단서입니다. pmap은 첫 번째 (+ 2 processors) 조각을 잡고 future을 통해 비동기 적으로 실행합니다. 따라서 코어가 2 개있는 경우 한 번에 4 조각을 시작하여 조금 앞선 상태로 유지하려고 시도하지만 최대 값은 2 + n이어야합니다.

future은 궁극적으로 제한되지 않은 수의 스레드를 지원하는 에이전트 I/O 스레드 풀을 사용합니다. 그것은 쓰레기가 쓰레기로 쓰인대로 성장할 것이고 쓰레드가 사용되지 않는다면 줄어들 것입니다.

어떻게 pmap의 작품을 설명 알렉스의 훌륭한 대답에
+1

많은 웹 호출을 처리하고 응답을 처리 할 때'pmap'이 완벽하게 괜찮습니까? 거기에 어떤주의 사항이 있습니까? – dan

+4

내가 틀렸을 수도 있지만 문제는 아마도 n + 2 스레드가 웹 응답을 기다리는 것을 차단할 것입니다. 따라서 최대 처리량에 대한 충분한 요청을 얻을 수 없습니다. pmap은 실제로 CPU 바인딩 작업 부하를위한 것입니다. 이런 일이 발생하면 미래에 각 요청 통화를 래핑 할 수 있으며 모두 즉시 중단됩니다. – mikera

+4

그럼 동시성에 대한 짧은 대답은 없습니다. :) 필자는 pmap이이 사용 사례에 실제로 이상적이지 않다고 말하고 싶습니다. 소스의 모든 *을 병렬로 기다리기를 정말로 원합니다 - pmap은 위의 경우에서 5 번째 시작을 지연시킵니다.Pmap의 게으른 행동이 좋은 경우라면, 모든 소스를 다 통과하기를 원하지 않는다면 말이다. 대신에 당신의 물건이 소스를 맵핑하고 미래를 사용하여 각 요청을하도록 유혹받을 것입니다. –

9

건물, 여기에 상황에 내 제안이다 :

(doall 
    (map 
    #(future (my-web-fetch-function %)) 
    list-of-xml-feeds-to-fetch)) 

이론적 근거 :

  • 당신은 기내 작업의 많은 부분 당신이 할 수 원하는 대부분의 경우 네트워크 IO에서 차단됩니다.
  • Future는 스레드 풀에서 처리되도록 각 요청에 대해 비동기 작업을 시작합니다. Clojure가이를 지능적으로 처리하도록 할 수 있습니다.
  • 지도상의 doall은 전체 시퀀스 (예 : 모든 요청 실행)를 강제로 평가합니다.
  • 주 스레드는 바로 미래를 역 참조 시작할 수 있으며, 각각의 결과를 다시
+0

미래는 무제한 스레드 풀을 사용하므로 대량의 피드 모음에서이를 실행하면 문제가 발생할 수 있다고 생각합니다. – Glen

+1

또한 모든 것을 마쳤을 때 알 수 있도록 미래를 'deref'하기 위해 다시 매핑해야 할 것입니다. – Joe

3

긴 응답을 작성하는 시간이 올 따라서 진전을 계속할 수 있지만, clojure.contrib HTTP 에이전트가있다있는 각각의 get/post 요청을 자체 에이전트로 작성합니다. 따라서 수천 건의 요청을 처리 할 수 ​​있으며 결과가 나오면 모두 병렬로 실행하여 완료 할 수 있습니다.

0

pmap의 작동을 보면 한 번에 32 개의 스레드가있는 것으로 보입니다. 문제는지도가 계산에 앞서 32 씩 진행되고 미래가 스스로 시작된다는 것입니다. (샘플) (defn samplef [n] (println "starting " n) (Thread/sleep 10000) n) (def result (pmap samplef (range 0 100)))

; 33 초를 기다릴 때 10 초를 기다린 다음 32 장을보고; 한 번에 32 개의 동시 스레드를 수행 중이라는 분을 인쇄합니다. ; 나에게 이것은 완벽하지 않다. ; SALUDOS Felipe