Rob*_*yre 7 parallel-processing optimization performance clojure map
假设我用以下方式定义所有自然数的序列:
(def naturals (iterate inc 0))
Run Code Online (Sandbox Code Playgroud)
我还定义了一个将自然映射到nil的函数,需要一段时间来计算,如下所示:
(defn hard-comp [_] (Thread/sleep 500))
Run Code Online (Sandbox Code Playgroud)
请注意计算时间以按照度量来评估以下s表达式clojure.core/time
.
(dorun (map hard-comp (range 30))) ;
15010.367496毫秒
(dorun (pmap hard-comp (range 30))) ;
537.044554 msecs
(dorun (map hard-comp (doall (take 30 naturals))))) ;
15009.488499 msecs
(dorun (pmap hard-comp (doall (take 30 naturals)))) ;
3004.499013毫秒
(doall (take 30 naturals)) ;
0.385724毫秒
(range 30)
; 0.159374毫秒
pmap
使用显式范围调用时比使用自然部分快6倍.
由于(= (range 30) (take 30 naturals))
返回true并且两个对象都是类型clojure.lang.LazySeq
,并且clojure在调用函数之前调用函数的所有参数,如何解释上述时序细节?
我的猜测是因为这个原因:
user> (chunked-seq? (seq (range 30)))
true
user> (chunked-seq? (seq (take 30 naturals)))
false
user> (class (next (range 30)))
clojure.lang.ChunkedCons
user> (class (next (take 30 naturals)))
clojure.lang.Cons
Run Code Online (Sandbox Code Playgroud)
试试这个:
user> (defn hard-comp [x] (println x) (Thread/sleep 500))
#'user/hard-comp
user> (time (dorun (pmap hard-comp (range 100))))
Run Code Online (Sandbox Code Playgroud)
请注意,它一次跳转32个项目.这是一个范围内每个块抓取的元素数量.Chunked seqs提前预先评估了一堆项目以提高性能.在这种情况下,pmap
只要您尝试从该范围中获取一个元素,它就会看起来像是大块地生成32个线程.
您可以随时将自然填充到矢量中以获得分块行为.
user> (time (dorun (pmap hard-comp (range 100))))
"Elapsed time: 2004.680192 msecs"
user> (time (dorun (pmap hard-comp (vec (take 100 naturals)))))
"Elapsed time: 2005.887754 msecs"
Run Code Online (Sandbox Code Playgroud)
(注意,时间大约是4 x 500 ms,4是到达100所需的32个块的数量.)
另一方面,您可能不想要分块行为.一次32个线程很多.有关如何取消seq化seq的示例,请参阅此问题.
归档时间: |
|
查看次数: |
836 次 |
最近记录: |