2010-09-19 13 views
4

我擔心這一點。
想象一下,最簡單的版本控制方式,即程序員只需複製主存儲庫中的所有目錄,並且在更改文件後,如果主存儲庫仍然相同,則會反向執行。如果它被另一個人改變了,他們必須再試一次。Clojure參考文獻的線程越多,每個線程的重試次數就越多?

當程序員的數量增加時,重試次數也增加是很自然的,但它可能與程序員的數量不成比例。
如果十個程序員的工作和一個工作需要一個小時,每個人,完成所有工作十小時至少需要。
如果他們認真的話,大約9 + 8 + 7 + ... 1 = 工時無所事事。
一個程序員的hundread,約99 + 98 + ... 1 = 工時沒空。

我試圖計算重試次數並得到結果。

來源

(defn fib [n] 
    (if (or (zero? n) (= n 1)) 
     1 
     (+ (fib (dec n)) (fib (- n 2))))) 

(defn calc! [r counter-A counter-B counter-C n] 
    (dosync 
    (swap! counter-A inc) 
    ;;(Thread/sleep n) 
    (fib n) 
    (swap! counter-B inc) 
    (alter r inc) 
    (swap! counter-C inc))) 

(defn main [thread-num n] 
    (let [r (ref 0) 
     counter-A (atom 0) 
     counter-B (atom 0) 
     counter-C (atom 0)] 
    (doall (pmap deref 
       (for [_ (take thread-num (repeat nil))] 
       (future (calc! r counter-A counter-B counter-C n))))) 
    (println thread-num " Thread. @ref:" @r) 
    (println "A:" @counter-A ", B:" @counter-B ", C:" @counter-C))) 

CPU:2.93GHz的四核英特爾酷睿i7
結果

user> (time (main 10 25)) 
10 Thread. @ref: 10 
A: 53 , B: 53 , C: 10 
"Elapsed time: 94.412 msecs" 
nil 
user> (time (main 100 25)) 
100 Thread. @ref: 100 
A: 545 , B: 545 , C: 100 
"Elapsed time: 966.141 msecs" 
nil 
user> (time (main 1000 25)) 
1000 Thread. @ref: 1000 
A: 5507 , B: 5507 , C: 1000 
"Elapsed time: 9555.165 msecs" 
nil 

我換了工作,(主題/睡眠N),而不是(FIBñ )並得到了類似的結果。

user> (time (main 10 20)) 
10 Thread. @ref: 10 
A: 55 , B: 55 , C: 10 
"Elapsed time: 220.616 msecs" 
nil 
user> (time (main 100 20)) 
100 Thread. @ref: 100 
A: 689 , B: 689 , C: 117 
"Elapsed time: 2013.729 msecs" 
nil 
user> (time (main 1000 20)) 
1000 Thread. @ref: 1000 
A: 6911 , B: 6911 , C: 1127 
"Elapsed time: 20243.214 msecs" 
nil 

在線程/睡眠的情況下,我認爲重試可能增加超過這個結果,因爲CPU是可用的。
爲什麼不重試增加?

謝謝。

+0

這看起來像的就業人數大致呈線性縮放。我肯定錯過了什麼。什麼擔心你的結果? – brice 2010-09-20 11:59:20

+0

我通過不使用pmap獲得了相關結果。我擔心發生了很多重試,這會浪費資源。 – 2010-09-20 20:14:01

回答

5

因爲你實際上並沒有產生10,100或1000個線程!創建一個futuredoes not always create a new thread。它使用a thread pool behind the scenes來保持排隊作業(或Runnable是技術性的)。線程池是一個緩存的線程池,它重用線程來運行作業。

所以在你的情況下,你實際上並沒有產生1000個線程。如果您想要查看重試次數,請獲得低於future的級別 - 創建您自己的線程池並將Runnable秒加入其中。

+0

我已經理解了。謝謝! – 2010-09-19 19:26:57

+1

還有一點提示:clojure函數*是*'Runnable's。 – kotarak 2010-09-20 06:26:51

+1

我注意到pmap spawn 2 +一次處理器的數量和將來使用的Executors.newCachedThreadPool()可以創建一個新的線程到Integer.MAX_VALUE。所以這個不協調的結果是pmap問題。 – 2010-09-20 19:59:12

1

自答案

我已經修改的主要功能不使用pmap,得到了結果,其制定的計算。

(defn main [thread-num n] 
    (let [r (ref 0) 
     counter-A (atom 0) 
     counter-B (atom 0) 
     counter-C (atom 0)] 
    (doall (map deref (doall (for [_ (take thread-num (repeat nil))] 
        (future (calc! r counter-A counter-B counter-C n)))))) 
    (println thread-num " Thread. @ref:" @r) 
    (println "A:" @counter-A ", B:" @counter-B ", C:" @counter-C))) 

FIB

user=> (main 10 25) 
10 Thread. @ref: 10 
A: 55 , B: 55 , C: 10 
nil 
user=> (main 100 25) 
100 Thread. @ref: 100 
A: 1213 , B: 1213 , C: 100 
nil 
user=> (main 1000 25) 
1000 Thread. @ref: 1000 
A: 19992 , B: 19992 , C: 1001 
nil 

線程/睡眠

user=> (main 10 20) 
10 Thread. @ref: 10 
A: 55 , B: 55 , C: 10 
nil 
user=> (main 100 20) 
100 Thread. @ref: 100 
A: 4979 , B: 4979 , C: 102 
nil 
user=> (main 1000 20) 
1000 Thread. @ref: 1000 
A: 491223 , B: 491223 , C: 1008 
nil