2011-12-25

fill-queueでお手軽非同期処理

この記事はClojure Advent Calendar 2011の25日目の記事として書いています。
あんまりホリデイっぽくないので、Overtoneの記事と入替えて読むとちょうどいいですよ。

前にClojureのシーケンス操作関数の使い方一覧を書いたけど、最後に例示を挙げられなかったものがふたつ残りました。
seq-onは「何かをシーケンスとして扱いたいとき」というわり合い特殊なものなので良いとして、fill-queueはもう少し便利に使えそうなものなので何とか例示ができないかなーと思って簡単なファイルの変更監視スクリプトを書いてみました。

まずはfill-queueのdocを見てみましょう。
user=> (doc fill-queue)
-------------------------
clojure.contrib.seq/fill-queue
([filler-func & optseq])
  filler-func will be called in another thread with a single arg
  'fill'.  filler-func may call fill repeatedly with one arg each
  time which will be pushed onto a queue, blocking if needed until
  this is possible.  fill-queue will return a lazy seq of the values
  filler-func has pushed onto the queue, blocking if needed until each
  next element becomes available.  filler-func's return value is ignored.
nil

どうやら別スレッドで実行させる関数filler-funcを指定して、その関数でゴニョゴニョした値をqueueシーケンスとして受け取れるということらしい。filler-func内から値を返すときは引数fillに渡す。
非同期処理をシーケンスの流儀で取り扱えるっていうやつみたいですね。

これだけだとイメージが沸かないので使用例をぐぐってみたらこんな記事が見つかりました。
The Infolace Story: Simple webhooks with Clojure and Ring
この海外記事を読むとRingサーバー処理になにかフックさせるときに使ってる。途中の図がわかりやすい。

これでも使用例としてはいいんですけど、もうちょっと手元でいじれる例が欲しいのでファイルの最終更新日時を監視するスクリプトを書いて見ました。



watching-loopがfiller-funcで実行される本体です。ループで1秒ごとにファイルの最終更新日時を監視、変わっていたらfillにプッシュ。スレッド名を出力するコードを入れてるので別スレッドで実行されてることがはっきりしますね。
実行するとこんな感じ。


$ echo happy > test.txt
$ clj watch-file-status.clj test.txt
watching... (seq-test.txt)
main thread: main
watching-loop thread: pool-2-thread-1
;; $ echo chrismas! >> test.txt
modified: seq-test.txt
datetime: 2011-12-25 11:29:28
;; Ctrl-C
$ cat test.txt 
happy
chrismas!


これでfill-queueの使用例を書くことができました。前々から気になってたのをアウトプットできてスッキリ。
もうクリスマスがどうとか言ってる時期じゃないよ! 大掃除、棚卸しが大事だよ! リア充が爆発したら掃除が大変だよ!

ではみなさん良い年末を。俺は年賀状を書きます。

0 件のコメント: