ウォッチャー
AnyEventでプログラムを作成する場合
現在から5秒後にコールバック関数を呼び出してもらうにはリスト1のようなコードを書きます。
use strict;
use AnyEvent;
my $cv = AnyEvent->condvar; ……(1)
# タイマーウォッチャーを作成
my $w; $w = AnyEvent->timer(
after => 5, # 今から5秒経ったらイベント発生
cb => sub { # イベント発生時にこの関数が呼ばれる
warn "5秒経ちました!";
undef $w; ……(2)
$cv->send;
}
);
$cv->recv; ……(3)
リスト1
リスト1
AnyEventにはこのタイマーのほかにもいくつかのウォッチャーオブジェクトが存在します。書き出してみるとその種類が意外と少ないことに驚かれるかもしれませんが、
それではどのようなウォッチャーがあるのか見てみましょう。
タイマーウォッチャー
|
まずは先述したタイマーウォッチャーです。このウォッチャーは任意のタイミングでイベントを発生させます。リスト2の場合、
my $w; $w = AnyEvent->timer(
after => 10,
cb => sub {
warn "10秒経ったよ!";
undef $w;
}
);
タイマーは任意のタイミングだけでなく、
my $count = 0;
my $w; $w = AnyEvent->timer(
after => 10, ……(1)
interval => 1, ……(2)
cb => sub {
$count++;
warn "タイマー発動! ($count回目)";
if ($count >= 10) {
undef $w;
}
}
);
タイマーを使用する際に重要なのは、
I/Oウォッチャー
|
I/
fhには監視するファイルハンドルを指定します。pollにはそのファイルハンドルに対して読み込み/"r"
"w"
リスト4の場合、"w"
を指定したため)
my $fh = ....; # ソケットなど
my $io; $io = AnyEvent->io(
fh => $fh, ……(1)
poll => "w", ……(2)
cb => sub {
# 実際に使う際は、syswriteのエラーなどを
# もっと確認してください
syswrite( $fh, "hoge hoge hoge" );
undef $io;
}
);
これを使ってソケットなどから読み込み可能になったら読み込めるだけ読み込むようなコードを書く場合はリスト5のようにします。
my $io; $io = AnyEvent->io(
fh => $fh,
poll => "r",
cb => sub {
my $len = sysread( $fh, my $buf, 8192 );
if ($len > 0) {
print "read '$buf'\n";
} elsif (defined $len) {
# ハンドルがcloseされた
undef $io;
} elsif ( $! != EAGAIN && $! != EINTR ) {
# よくないエラー
undef $io;
die "An error occurred: $!";
}
}
);
このしくみを利用して複数のホストに同時接続しながらそれぞれの接続が読み込み可能になったところからコンテンツをダウンロードするということもできますが、
アイドルウォッチャー
|
イベントループが回っていても、
このウォッチャーは何か処理を行う必要があるものの、after => 0
)
my $cv = AnyEvent->condvar;
my $count = 1;
my $t; $t = AnyEvent->timer(
after => 0,
interval => 1,
cb => sub {
warn "timer!";
if ($count++ > 10) {
undef $t; ……(1)
$cv->send;
}
}
);
my $w; $w = AnyEvent->idle(
cb => sub {
warn "idle";
undef $w;
}
);
$cv->recv;
なお、
シグナルウォッチャー
|
シグナルウォッチャーは、
my $w; $w = AnyEvent->signal(
signal => 'INT',
cb => sub {
# クリーンアップ処理
undef $w;
}
);
なお、
コンディション変数
先ほど少し紹介したコンディション変数は、
特定の条件が満たされるまで待つ
一番わかりやすい使用方法はなんらかの条件が満たされるまで処理をそこでブロックするために使うことです。
まず簡単な例として、
use strict;
use AnyEvent;
my $cv = AnyEvent->condvar; ……(1)
my $w; $w = AnyEvent->timer(
after => 10,
cb => sub {
undef $w;
$cv->send; ……(2)
}
);
$cv->recv; ……(3)
このスクリプトを
リスト8では、
タイマーウォッチャーが起動すると、
なお、
複数の条件が満たされるまで待つ
リスト8ではsendを1回呼べば条件が満たされましたが、
use strict;
use AnyEvent;
my $cv = AnyEvent->condvar( cb => sub { ……(1)
warn "executed all timers";
});
for my $i (1..10) {
$cv->begin; ……(2)
my $w; $w = AnyEvent->timer(after => $i, cb => sub {
warn "finished timer $i";
undef $w;
$cv->end; ……(3)
});
}
$cv->recv; ……(4)
タイマーがそれぞれ発動するコールバックの中の
処理終了時のコールバックとして使う
最後の使い方は、
簡単な例はすでにリスト9で解説しましたが、
use strict;
use AnyEvent;
AnyEvent::Util::fh_nonblocking(\*STDIN, 1);
sub read_stdin {
my $cv = AnyEvent->condvar;
my $w; $w = AnyEvent->io(
fh => \*STDIN,
poll => 'r',
cb => sub {
undef $w;
my $line = <STDIN>;
$cv->send( $line );
}
);
return $cv;
}
my $main_cv = AnyEvent->condvar;
{ # 1個目。こちらはSTDERR にprint ……(1)
my $cv = read_stdin();
$cv->cb( sub {
my ($line) = $_[0]->recv;
print STDERR "STDERR: got $line";
$main_cv->send;
} );
}
# 1個目の読み込みが終わるまで待機……
$main_cv->recv;
$main_cv = AnyEvent->condvar;
{ # 2個目。こちらはSTDOUTにprint ……(2)
my $cv = read_stdin();
$cv->cb( sub {
my ($line) = $_[0]->recv;
print STDOUT "STDOUT: got $line";
$main_cv->send;
} );
}
# 2個目の読み込みが終わるまで待機……
$main_cv->recv;
read_
コンディション変数はこのほかにも、