2015-10-19 35 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。这些工作将单个计算的工作分解为可并行的部分,然后将它们组合在一起。这些将有效地运行在您的计算机所具有的尽可能多的内核上。如果你用未来或者在一个块中运行你的每个计算,那么每个计算将在一个线程上运行,有些可能会在其他线程之前完成,并且这些核心将空闲。