2013-02-11 33 views
8

kullanarak büyük sayıdaki sayıların toplamını nasıl hesaplayabilirim? Basit bir işlemi büyük bir sıraya paralel olarak verimli bir şekilde uygulamak için clojure'un nasıl kullanılacağını anlamaya çalışıyorum. Makinemdeki birden fazla çekirdekten yararlanmak için paralel çözümü kullanabilmek için hızlandırmak istiyorum.Clojure

Giriş bölümündeki her öğe için bir geleceği oluşturmanın ek yükünü azaltmak için pmap'i bölümleme ile birlikte kullanmaya çalışıyorum. Ne yazık ki, bölüm-tüm her bölümün tam değerlendirmesini zorlar. Bu, makinemde bir OutOfMemoryError neden olur.

(defn sum [vs] 
    (reduce + vs)) 

(def workers 
    (+ 2 (.. Runtime getRuntime availableProcessors))) 

(let 
    [n 80000000 
    vs (range n)] 

    (time (sum vs)) 
    (time (sum (pmap sum (partition-all (long (/ n workers)) vs))))) 

Büyük bir girdi kümesine toplamı nasıl uygulayabilirim ve seri uygulamanın performansını nasıl kullanabilirim?

Çözüm düşürücüler kütüphanesini işaret için @Arthur Ulfeldt için

teşekkür ederiz. İşte redüktörleri kullanarak çözüm. Bu kod, çok çekirdekli bir makinede çalışırken beklenen performans artışını gösterir. bir parça deneyin ben oldukça büyük parçalar geçiş aşmak için gerekli olduğunu bulduk pmap ve gelecek havai kullanırken

(require '[clojure.core.reducers :as r]) 

(let 
    [n 80000000 
    vs #(range n)] 

    (time (reduce + (vs))) 
    (time (r/fold + (vs))) 
+0

parçalar yanlış yol Are etrafında? '(bölüm-tüm işçiler vs)' '(/ n işçi)' uzunluklarını 'işçi' dizileri oluşturur. Sen istemiyor musun (tüm bölüm (uzun (/ işçi)) vs) '? –

+0

@ A.Webb, düzeltmeniz için teşekkür ederiz. Soruyu değiştireceğim. Bu düzeltme, paralel sürümü biraz daha hızlı hale getirmeye yardımcı olur, ancak yine de seri uygulamayı yenemez ve hala çok büyük girişlerde bellek yetersiz kalır. –

cevap

8

: (NOT Zamanlamanın daha doğru hale getirmek için bir işlev olması vs değişti) + kadar hızlı bir zıtlık için 10.000 büyüklük. Potansiyel kazançlar, parçaların oluşturulmasının ek yükü ile sınırlandırılmaktadır. Bu, mevcut çekirdekleri ve parçaları yapmak için gereken süreyi dengeleyen optimal bir değere neden olur. Bu durumda iş yükü olarak + ile bunu tek iş parçacığı seçeneğinden daha hızlı yapamadım.

potansiyel çatal kullanarak pmap olmadan bunu ve ilgileniyorsanız/yeni (imsi) kontrol katılmak reducers library

OOM durum daha sonra korunur (range n) gelen tembel diziyi gerçekleştiren ilk testte geliyor böylece ikinci diziye geçirilebilir.

Ben slow+ fonksiyonunu tanımlayarak + fonksiyonu çok daha yavaş yapabilir ve tek iplik, parçalar üzerinde pmap ve düşürücüler arasındaki diference w/vize hale forkJoin o kullanıyorsanız:

user> *clojure-version*                
{:major 1, :minor 5, :incremental 0, :qualifier "RC15"} 
(require '[clojure.core.reducers :as r]) 

(def workers 
    (+ 2 (.. Runtime getRuntime availableProcessors))) 

(defn slow+ 
    ([] 0) 
    ([x] x) 
    ([x y] (reduce + (range 100000)) (+ x y))) 

(defn run-test [] 
    (let [n 8000] 
    (time (reduce slow+ (range n))) 
    (time (reduce slow+ (pmap #(reduce slow+ %) (partition-all (* workers 100) (range n))))) 
    (time (r/fold slow+ (vec (range n)))))) 

user> (run-test) 
"Elapsed time: 28655.951241 msecs" ; one thread 
"Elapsed time: 6975.488591 msecs" ; pmap over chunks 
"Elapsed time: 8170.254426 msecs" ; using reducer