AnyEvent でイベント駆動プログラミング
昨年の YAPC で非同期系のセッションが人気があったので、ちょっと遅いけど、手を出してみることにする。
AnyEvent を小2時間ほどいじってみたので、自分なりの解釈で記事を書くことにする。
イベント駆動プログラミングって何?
プログラムが上から下に実行される、いわゆる手続き型プログラミングとは違い、イベントハンドラにコールバック関数を登録しておき、イベントループを回します。イベント発生をトリガとして、イベントハンドラに登録されているコールバック関数を実行するプログラミング手法。
ちなみにイベントとは以下のようなことを指します。
- キーボード押された
- マウスがクリックされた
Windows プログラミングの経験者であれば、すんなり入っていくことができると思います。GetMessage のイベントループとか WindowProc とか例のやつです。僕も、Windows プログラミングの経験者だったので、すんなり入ることができました。
初めての AnyEvent
1秒毎に現在時刻を表示し、標準入力(STDIN)から「quit」が入力されるまで、監視をするプログラムのサンプルです。
#!/usr/bin/env perl use strict; use warnings; use feature qw/say/; use AnyEvent; # 1秒ごとに現在時刻を表示するイベント my $cvt = AnyEvent->condvar; my $t; $t = AnyEvent->timer( after => 0, interval => 1, cb => sub { say AnyEvent->time; $cvt->send; }, ); $cvt->recv; local $| = 1; # 標準入力から入力イベント # quit が入力されるとイベントループを抜ける IO: for (;;) { my $cv = AnyEvent->condvar; my $wait_for_input; $wait_for_input = AnyEvent->io( fh => \*STDIN, poll => 'rl', cb => sub { chomp(my $input = <STDIN>); undef $wait_for_input; $cv->send($input); } ); my $input = $cv->recv; say "[$input]"; last IO if defined $input && $input eq "quit"; } undef $t; say "done.";
ソースコードの前半では、タイマーのイベントを作成しています。interval で指定した秒数毎に登録してあるコールバック関数が呼び出される仕組みになっています。
ソースコードの後半では、標準入力を監視するイベントを作成しています。標準入力から入力があったときに、登録してあるコールバック関数が呼ばれる仕組みになっています。
ソースコード内に度々でてくる、AnyEvent->condvar は、状態変数と呼ばれるもので、メインループに対してイベントの状態を通知するための変数です。
$cv->send で状態変数を変更し、$cv->recv は状態変数が変更されるまで、つまり、$cv->send が呼び出されるまでコードをブロックしています。明快な説明じゃないですね。。ちゃんと説明できるようになったら修正しよう。
ちなみに実行してみるとこんな感じになります。
% perl ae3.pl 1269878022.06494 1269878023.06862 1269878024.0677 amar1269878025.06774 i3 [amari3] 1269878026.06878 1269878027.06878 quit [quit] done.
勉強を始めたばっかりで、説明に誤りがあるかもしれないけど、おもしろいので引き続き勉強していきます。