What have you found for these years?

2009-06-12

agent in clojure

http://clojure.org/agents

簡單地說就是可以想像成一種 single thread 裡的 message queue..
先定義 job:

   1  (def job (agent nil))

這邊的 nil 是隨便丟一個值進去,算是初始化吧。
   1  (send job (fn [_] (Thread/sleep 3000) {:id 100}))

這邊對 job 存入 {:id 100}, 這是一個 hash, 就像 {:id => 100}
但是這個動作是 asynchronous 的,也就是 send 會直接結束,
這裡的 fn (lambda) 會在背後執行,執行結果會寫入 job,
在這裡就是這個 hash map. 因此,如果我們事後這樣叫...
user=> job
#Agent@847fc71: nil
user=> job
#Agent@847fc71: nil
user=> job
#Agent@847fc71: nil
user=> job
#Agent@847fc71: nil
user=> job
#Agent@847fc71: {:id 100}

要到第三秒後,才能看到 job 被寫入 {:id 100}
但這也不需要像是 poll 去看到底寫入了沒?
直接寫:
   1  (send job println)

然後就可以注意到三秒後會自動執行 println, 而這也不會是 blocking 的。

這樣是還不錯,不過網頁上的例子我是覺得有點奇怪,
稍微試了一下才搞懂他想做什麼。簡單地說,他產生 1000 個 agent,
然後把 0~999 都丟給這 1000 個 agent, 因此總共是 1 million message.
最後在最後一個序號和最後一個 agent 收到訊息時,
塞一個值到 SynchronousQueue 裡。在 run 的最後,
再從這個 SynchronousQueue 裡抓一個東西出來,
而這件事本身是 blocking 的。
因此... 要跑完一百萬次,整個 run 才算是結束。

p.s. 他的 keyword, 也就是 :next 當成 function 時,
是檢查 hash map (table) 裡是否有該 keyword 的值。
有機會時可以玩玩看 clojure, 架構在 jvm 上真的是有好好壞...
首先最明顯的好處就是因為 jvm 大部份的人都有,
就不像 ruby 程式要拿給 windows 使用者跑,如此艱難...
   1  (defn relay [x i]
2 (when (:next x)
3 (send (:next x) relay i))
4 (when (and (zero? i) (:report-queue x))
5 (.put (:report-queue x) i))
6 x)
7
8 (defn run [m n]
9 (let [q (new java.util.concurrent.SynchronousQueue)
10 hd (reduce (fn [next _] (agent {:next next}))
11 (agent {:report-queue q}) (range (dec m)))]
12 (doseq [i (reverse (range n))]
13 (send hd relay i))
14 (.take q)))
15
16 ; 1 million message sends:
17 (time (run 1000 1000))
18 ->"Elapsed time: 2959.254 msecs"

0 retries:

Post a Comment

All texts are licensed under CC Attribution 3.0