mond-tech [perl]AnyEvent - 入力監視とタイムアウト 忍者ブログ
焼肉屋さんが大好きです。いや、そうでも無い。 たぷたぷになってきてピンチです。
05
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

多重IOをやる場合、何気にいろいろ面倒臭い事があるのだけれど(特にライブラリの依存関係周り)、
そんな悩みを一気に解消してくれるAnyEvent。
とても優れたライブラリなので使い方のメモを公開。

STDINを監視して、任意の秒数後にタイムアウトする、と言うサンプル。
入力が何も無い状態でEnter打たれたら、再び入力を催促。

alarm使った方が、いやむしろ、IO::Promptった方がコードごっそり減るけど、
あくまでAnyEventの書き方のサンプルって事で。AnyEvent::Introのサンプルにもあるしね、これ。


#!/usr/bin/perl

use strict;

use AnyEvent;

my $TIMEOUT = 3;

$| = 1;

my $condvar = AnyEvent->condvar;
my $watcher_stdin = watch_stdin($condvar);
my $watcher_timeout = watch_timeout($condvar);
main_loop($condvar);

sub watch_stdin {
my ($cv) = @_;
print 'INPUT: ';
return AnyEvent->io(
fh => \*STDIN,
poll => 'r',
cb => sub {
my $in = <>;
chomp $in;
if ($in ne '') { $cv->send($in); }
else { print 'INPUT: '; }
}
);
}

sub watch_timeout {
my ($cv) = @_;
return AnyEvent->timer(
after => $TIMEOUT,
cb => sub {
print "\ntimeout\n";
$cv->send('empty');
},
);
}

sub main_loop {
my ($cv) = @_;
print '> ' . $cv->recv . "\n";
}


解かりやすいように凄く大げさに書いた。
と言うか、まともにコード組むと、大概はこんな感じになるはず。

まず、AnyEventでは、ちょっと名前が微妙なcondvarを用いて、通信を行う。
具体的言うと、このcondvarオブジェクトのrecvを呼ぶと、
sendで値が与えられるまで、ブロッキングされる、と言う具合。

watch_stdinでは、io関数を用いてSTDINの監視を設定。
読み込み可能になった場合(つまり入力があった時)に動作する関数を、
cbの値として与える。pollには読み込み時と言う事で'r'。fhにはSTDINのグロブのリファレンス。
これはIO::Handle系のオブジェクトでも良い。
このコールバック関数の中で、STDINに対しての入力が空では無かった場合に、
condvarのsendを叩いて、値を入れる。

watch_timeoutでは、タイムアウトイベントをtimer関数を用いて指定。
afterで、タイムアウトまでの時間を設定。
timerでは、afterで指定した秒数後に、コールバックが実行される。

main_loopでは、condvarのrecvを呼んで、ブロッキング開始。

まぁ、簡単でしょう。

注意点としては、

my $watcher_stdin = watch_stdin($condvar);

こんな感じで、AnyEvent->ioやtimerから返ってくる値を必ず変数で受けること。
こうしないと、正常動作しない。

これは、AnyEventのguardと言うものを用いているから。詳しくは別で説明するけど、
大雑把に言うと、その変数が開放される際に呼ばれるコールバックを設定する事が出来る、と言うもの。
リソース開放系、ですわ。
PR
お名前
タイトル
文字色
URL
コメント
パスワード
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
Trackback URL
Copyright c mond-tech All Rights Reserved
忍者ブログ / [PR]
にほんブログ村 IT技術ブログ Webサイト構築へ