agent同期化のサンプル

agentをawait,await-for関数で同期化するサンプルを書いてみた。

send関数によるagentの更新は非同期で行なわれるが、await関数を使い、send関数で指示した関数の実行が完了するまで待機することができる。
待ち時間を指定したい場合はawait-for関数を使用する。

agent-sample.clj

; カウンタを初期値0のagentとして定義
(def counter (agent 0))

; 1秒待機した後、引数を1増やした値を返す関数
(defn count-fn [x]
     (Thread/sleep 1000)
     (inc x))

; 以下の処理を10回繰り返す。
;   (1)カウンタ値を増やす関数をsend関数で呼び出す。
;   (2)awaitまたはawait-forで(2)のsend関数によるagent更新が完了するまで待機する。
(dotimes [i 10]
  (send counter count-fn)
  (await counter)
;  (await-for 500 counter)
  (println (format "@counter=%d" @counter)))

awaitの場合の実行結果
await関数により、カウンタ値の更新が同期化されるため、カウンタ値は1ずつ増える。

user> (load-file "agent-sample.clj")
@counter=1
@counter=2
@counter=3
@counter=4
@counter=5
@counter=6
@counter=7
@counter=8
@counter=9
@counter=10
nil
user> @counter
10

await-forの場合の実行結果
await-forには500msecを指定しているため、カウンタ値は更新前の値となる。

user> (load-file "agent-sample.clj")
@counter=0
@counter=0
@counter=1
@counter=1
@counter=2
@counter=2
@counter=3
@counter=3
@counter=4
@counter=4
nil
user> @counter ←5秒ほど待ってから入力
10