2015-10-19 33 views
4

我已經開始使用clojure core.async庫。我發現CSP,通道,塊的概念非常易於使用。但是,我不確定我是否正確使用它們。我有下面的代碼 -用於數據計算的Clojure core.async

(def x-ch (chan)) 
(def y-ch (chan)) 
(def w1-ch (chan)) 
(def w2-ch (chan)) 

; they all return matrices 
(go (>! x-ch (Mat/* x (map #(/ 1.0 %) (max-fold x))))) 
(go (>! y-ch (Mat/* y (map #(/ 1.0 %) (max-fold y))))) 
(go (>! w1-ch (gen-matrix 200 300))) 
(go (>! w2-ch (gen-matrix 300 100))) 

(let [x1 (<!! (go (<! x-ch))) 
     y1 (<!! (go (<! y-ch))) 
     w1 (<!! (go (<! w1-ch))) 
     w2 (<!! (go (<! w2-ch)))] 

    ;; do stuff w/ x1 y1 w1 w2 
) 

我在符號xy了預定義的(矩陣)載體。在使用它們之前,我需要修改兩個矢量。那些矢量非常大。我還需要生成兩個隨機矩陣。由於go宏異步啓動計算,因此我將所有四個計算任務分解爲單獨的轉移塊,並將後續結果放入通道中。然後我得到一個讓我從這些通道獲取數值並將它們存儲爲符號的區塊。他們都使用阻止<!!採取功能,因爲他們在主線程。

我想要做的事情基本上是通過將程序片段拆分爲異步進程來加速我的計算時間。這是做到這一點的正確方法嗎?

+2

爲什麼你想在這裏使用異步代碼?異步代碼在您需要阻止和等待時有效。否則,它什麼都不做。當你只需要做數學運算時,你應該直接或並行計算它,例如將來。 – JustAnotherCurious

+0

謝謝你。在我的代碼中,我同時開始4次計算並阻止/等待值,直到它們返回某些值。這與異步塊/等待有何不同?然而,就像尼古拉斯和你指出的那樣,我將會爲此而使用未來。我能否在go塊中使用core.reducers?或者這會是一個可怕的想法? – Lordking

+0

你不能在同一時間啓動它們。所有內容都按順序執行,因爲在go塊中沒有有價值的阻止操作。我定義了函數「素數?」測試數字是否爲總數。看這裏:「(time(do(count(filter true)(map prime?(range 2 20000))))))」3 seconds and「(time(count(filter true)(map prime?(range 2 20000 )))))「給出3秒。您只使用一個線程,並且所有內容都是順序的。測試它! – JustAnotherCurious

回答

3

go塊返回通道與表達式的結果,所以你不需要爲他們的結果創造中間渠道。下面的代碼可以讓您同時啓動所有4個計算,然後阻止這些值直到它們返回。如果您不需要立即使用某些結果,則只有在實際使用該值時才能阻止該值。

(let [x1-ch (go (Mat/* x (map #(/ 1.0 %) (max-fold x)))) 
     y1-ch (go (Mat/* y (map #(/ 1.0 %) (max-fold y)))) 
     w1-ch (go (gen-matrix 200 300)) 
     w2-ch (go (gen-matrix 300 100)) 
     x1 (<!! x1-ch) 
     y1 (<!! y1-ch) 
     w1 (<!! w1-ch) 
     w2 (<!! w2-ch)] 
    ;; do stuff w/ x1 y1 w1 w2 
) 
+0

甜美。謝謝。使我的代碼更加簡潔 – Lordking

5

對於這種處理,future可能稍微更充足。

從鏈接的例子是簡單的把握:

(def f 
    (future 
    (Thread/sleep 10000) 
    (println "done") 
    100)) 

的處理,未來塊立即啓動,所以上面並啓動一個線程,等待「完成」完成後10秒,並打印。

當你需要的價值,你可以只使用:

(deref f) 
; or @f 

這樣就能夠阻止並返回未來的代碼塊的價值。

在同一個例子中,如果你在10秒鐘之前調用deref,那麼調用將被阻塞直到計算完成。

在你的例子中,因爲你只是等待計算完成,並沒有太多關注消息和渠道參與者之間的交互未來是我會推薦的。所以:

(future 
    (Mat/* x (map #(/ 1.0 %) (max-fold x)))) 
+0

謝謝尼古拉斯。我會試一試。不過,如果我不得不使用core.async,那麼對於我的實現有什麼想法?我正在努力掌握CSP。 – Lordking

1

如果你正在尋找更多的一般運行在並行代碼加速你的程序,那麼你可以看看使用Clojure的Reducers,或Aphyr的Tesser。這些工作將單個計算的工作分解爲可並行的部分,然後將它們組合在一起。這些將有效地運行在您的計算機所具有的儘可能多的內核上。如果你用未來或者在一個塊中運行你的每個計算,那麼每個計算將在一個線程上運行,有些可能會在其他線程之前完成,並且這些核心將空閒。