jne*_*ira 5 concurrency performance jvm clojure stm
我试图让clojure并发的"官方"示例更接近使用手动锁定的java版本.在这个要点中,我将java和clojure代码以及所有版本的VisualVm配置文件的线程转储.这是clojure代码和时间
(ns simple-example (:gen-class))
(set! *warn-on-reflection* true)
;; original from: http://clojure.org/concurrent_programming
(import '(java.util.concurrent Executors Future)
SimpleLocking$Node)
(defn test-concur [iter refs nthreads niters]
(let [pool (Executors/newFixedThreadPool nthreads)
tasks (map (fn [t]
(fn []
(dotimes [n niters]
(iter refs t))))
(range nthreads))]
(doseq [^Future future (.invokeAll pool tasks)]
(.get future))
(.shutdown pool)))
(defn test-stm [nitems nthreads niters]
(let [refs (vec (map ref (repeat nitems 0)))
iter #(dosync (doseq [r %] (alter r + 1 %2)))]
(test-concur iter refs nthreads niters)
(map deref refs)))
(defn test-atom [nitems nthreads niters]
(let [refs (vec (map atom (repeat nitems 0)))
iter #(doseq [r %] (swap! r + 1 %2))]
(test-concur iter refs nthreads niters)
(map deref refs)))
;; SimpleLocking$Node is the class with the synchronized method of java version
(defn test-locking [nitems nthreads niters]
(let [refs (->> (repeatedly #(SimpleLocking$Node.))
(take nitems) vec)
iter #(doseq [^SimpleLocking$Node n %] (.sum n (+ 1 %2)))]
(test-concur iter refs nthreads niters)
(map (fn [^SimpleLocking$Node n] (.read n)) refs)))
(definterface INode
(read [])
(add [v]))
(deftype Node [^{:unsynchronized-mutable true} value]
INode
(read [_] value)
(add [this v] (set! value (+ value v))))
(defn test-locking-native [nitems nthreads niters]
(let [refs (->> (repeatedly #(Node. 0))
(take nitems) vec)
iter #(doseq [^Node n %]
(locking n (.add n (+ 1 %2))))]
(test-concur iter refs nthreads niters)
(map (fn [^Node n] (.read n)) refs)))
(defn -main [& args]
(read-line)
(let [[type nitems nthreads niters] (map read-string args)
t #(apply + (time (% nitems nthreads niters)))]
(case type
'lock (println "Locking:" (t test-locking))
'atom (println "Atom:" (t test-atom))
'stm (println "STM:" (t test-stm))
'lock-native (println "Native locking:" (t test-locking-native)))))
Run Code Online (Sandbox Code Playgroud)
时间(在"老"英特尔核心组合中):
Java version
int nitems=100;
int nthreads=10;
final int niters=1000;
Sum node values: 5500000
Time: 31
simple-example=> (-main "lock" "100" "10" "1000")
"Elapsed time: 60.030324 msecs"
Locking: 5500000
nil
simple-example=> (-main "atom" "100" "10" "1000")
"Elapsed time: 202.309477 msecs"
Atom: 5500000
nil
simple-example=> (-main "stm" "100" "10" "1000")
"Elapsed time: 1830.568508 msecs"
STM: 5500000
nil
simple-example=> (-main "lock-native" "100" "10" "1000")
"Elapsed time: 159.730149 msecs"
Native locking: 5500000
nil
Run Code Online (Sandbox Code Playgroud)
注意:我不希望像java一样快速获得clojure版本,或者使用lock one获得与clojure一样快的stm版本.我知道这通常是困难的,有些问题是不可能的.我知道使用原子和stm比使用手动锁更易组合,更易于使用且更不容易出错.这些版本只是java和clojure中最好的参考问题(我做到了最好).我的目标是使原子和stm版本更接近锁定版本,或者理解为什么(可能在这个具体示例中)不可能加速这些版本.
注意:另一个比较,这次是使用STM和MVars的haskell版本(相同的gist链接的代码):
>SimpleExampleMVar 100000 1000 6
Starting...
2100000000
Computation time: 11.781 sec
Done.
>SimpleExampleSTM 100000 1000 6
Starting...
2100000000
Computation time: 53.797 sec
Done.
>java -cp classes SimpleLocking
Sum node values: 2100000000
Time: 15.703 sec
java -cp classes;%CLOJURE_JAR% simple_example lock 1000 6 100000
"Elapsed time: 27.545 secs"
Locking: 2100000000
java -cp classes;%CLOJURE_JAR% simple_example lock-native 1000 6 100000
"Elapsed time: 80.913 secs"
Native locking: 2100000000
java -cp classes;%CLOJURE_JAR% simple_example atom 1000 6 100000
"Elapsed time: 95.143 secs"
Atom: 2100000000
java -cp classes;%CLOJURE_JAR% simple_example stm 1000 6 100000
"Elapsed time: 990.255 secs"
STM: 2100000000
Run Code Online (Sandbox Code Playgroud)
您并不是真的像这里一样进行比较 - Clojure 版本正在创建和交换新的不可变盒装数字,而 Java 版本只是int在同步方法中碰撞可变基元计数器。
您可以在 Clojure 中执行常规 Java 风格的手动锁定,如下所示:
(locking obj (set! (. obj fieldName) (+ 1 (.fieldName obj)))))
Run Code Online (Sandbox Code Playgroud)
该locking构造实际上相当于 Javasynchronized代码块。
如果您使用类型提示的 Java 对象或带有字段的 Clojure deftype 来执行此操作:unsynchronized-mutable,那么我认为您应该能够匹配纯 Java 同步性能。
还没有测试过这个,但我认为它也应该适用于基元(如果您增加long计数器等,这可能很有用)
| 归档时间: |
|
| 查看次数: |
899 次 |
| 最近记录: |