clojureは並行処理を得意としているので各処理が独立してできる場合、並行で処理をさせると高速化できる場合があります。代表的な関数としてはpmap、pvalues、pcallなど。
pmap
vectorの各要素に関して、ある処理を回したいとかの場合、pmapがよいでしょう。たぶん一番これがよく使う。
user=> (pmap #(+ 1 %) [1 2 3 4 5]) (2 3 4 5 6)
ここでは+1するだけの軽い処理ですが、pmapをするような場合はある程度重い関数でないとオーバーヘッドのほうが大きくなってしまいます。そういう場合はよくsequenceをpartitionしてからpmapし、flattenするというのがよくやられます(たぶん)。元々のseqがネストしてたりするとflattenした場合予想以上にflattenされてくるので、注意が必要。
(def N 10000) (def long-seq (range N)) (flatten (pmap #(map + %) (partition (/ N 5) long-seq)))
この場合は5分割してやっている例。使えるコア数とかに応じて変えるとよい。
pvalues
並行で処理したいのがvectorの要素、とかではなく、いくつかの式を並行でやりたい場合に使う。こんな感じ。
(pvalues (heave-calc1 x y) (heave-calc2 x y) (heave-calc3 x y))
pcalls
引数と取らない関数を並行で処理させたい場合に使う。こんな感じ。
(pcall function-1 function-2 ...)
pvaluesの中身を見るとpcallsで定義されているのが分かる。
(defmacro pvalues "Returns a lazy sequence of the values of the exprs, which are evaluated in parallel" {:added "1.0" :static true} [& exprs] `(pcalls ~@(map #(list `fn [] %) exprs)))