2013-02-11 3 views
8

clojureを使用して簡単な操作を効率的に大規模なシーケンスに並列で適用する方法を理解しようとしています。並列ソリューションを使用して、マシン上の複数のコアを利用してスピードアップを実現したいと考えています。Clojureを使用して多数の数値の合計を計算するには

私は、入力seqのすべてのアイテムの未来を作成するオーバーヘッドを減らすために、partition-allと組み合わせてpmapを使用しようとしています。残念ながら、partition-allは各パーティションseqの完全な評価を強制します。これは私のマシン上でOutOfMemoryErrorを引き起こします。

(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))))) 

大きな入力セットに合計を適用してシリアル実装のパフォーマンスを上げるにはどうすればよいですか?レデューサーライブラリを指摘して@Arthur Ulfeldtへ

ソリューション

感謝。ここに、減速器を使用したソリューションがあります。このコードは、マルチコアマシンで実行した場合の予想されるパフォーマンスの向上を示しています。チャンクを試してみてください、私はかなり大きな塊がスイッチングを克服するために必要であることを見出したのpmapおよび将来のオーバーヘッドを使用する場合

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

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

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

は間違った方法塊です周り? '(partition-all workers vs)'は長さ 'workers 'の'(/ n workers) 'シーケンスを作成します。あなたは '(パーティション全部(長い(/ n人)対)vs)'をしたくないですか? –

+0

@A.Webb、訂正していただきありがとうございます。私はその問題を修正するつもりです。この修正により、並列バージョンは少し速くなりますが、それでもシリアル実装を破ることはできず、非常に大きな入力ではメモリ不足になります。 –

答えて

8

:(注私はタイミングがより正確にするために機能をする対変更されています) +と同じくらい早い時期に10,000のサイズ。潜在的な利益は、チャンクを生成するオーバーヘッドによって制限されます。これにより、利用可能なコアとチャンクの作成に必要な時間とのバランスをとる最適な値が得られます。この場合、ワークロードとして+を使用すると、シングルスレッドオプションよりも高速にすることができませんでした。

あなたはPMAPせずにこれを行うに興味がある、潜在的にフォークを使用している場合は/新しい(っぽい)をチェックしてください参加reducers library

OOM状況は、保持され(range n)から怠惰なシーケンスを実現する最初のテストから来ています2番目のシーケンスに渡すことができます。

私はslow+関数を定義することによって、はるかに遅い+の機能を作成し、forkJoin visableになる/ wのことをシングルスレッド、チャンクを超えるPMAP、及び減速の間diferenceを使用する場合:

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 
関連する問題