あだ名の多さは人気の証明?
POEという名前にはあきれるほど多くの寓意がこじつけられています。もともとはPerl Object Environment
20世紀最後の大規模プロジェクト
POEが生まれたのは1998年8月のこと。翌1999年の8月には第3回のPerlカンファレンス
20世紀生まれのPOEが
その一方で、
簡単なスクリプトをPOEで書き直してみよう
伝統的なPerlスクリプトは、
use strict;
use warnings;
package MyObj;
sub new {
my ($class, @files) = @_;
bless { files => \@files }, $class;
}
sub do_tasks {
my $self = shift;
while ( my $file = shift @{$self->{files}} ) {
print "processing $file\n";
# 実際にはファイルの解析や圧縮、ダウンロードなどの
# もっと具体的な処理が入るところです
my $counter = int(rand(1_000_000));
1 while $counter--;
}
}
package main;
my $obj = MyObj->new(1..100);
$obj->do_tasks;
POEの場合も、
package main;
use POE;
POE::Session->create(
heap => { obj => MyObj->new(1..100) },
inline_states => {
_start => sub { $_[KERNEL]->yield('do_tasks') },
do_tasks => sub { $_[HEAP]{obj}->do_tasks },
},
);
POE::Kernel->run;
いささか見慣れない表現もありますが、
セッションが始まるとまず_startに登録されている処理が実行されます
シングルタスクからマルチタスクへ
まずはセッションを登録する部分をこのように変えてみます。
POE::Session->create(
heap => { obj => MyObj->new(1..100) },
inline_states => {
_start => sub {
$_[KERNEL]->yield('do_tasks');
$_[KERNEL]->yield('tick');
},
do_tasks => sub { $_[HEAP]{obj}->do_tasks },
tick => sub {
print "tick\n";
$_[KERNEL]->delay(tick => 1);
},
},
);
ところが、
use strict;
use warnings;
package MyObj;
sub new {
my ($class, @files) = @_;
bless { files => \@files }, $class;
}
sub do_task {
my $self = shift;
my $file = shift @{$self->{files}} or return;
print "processing $file\n";
my $counter = int(rand(1_000_000));
1 while $counter--;
return 1;
}
package main;
use POE;
POE::Session->create(
heap => { obj => MyObj->new(1..100) },
inline_states => {
_start => sub {
$_[KERNEL]->yield('do_task');
$_[KERNEL]->yield('tick');
},
do_task => sub {
$_[HEAP]{obj}->do_task and $_[KERNEL]->yield('do_task');
},
tick => sub {
print "tick\n";
$_[KERNEL]->delay(tick => 1);
},
},
);
POE::Kernel->run;
これでずいぶんマシになりました。do_
POE::Session->create(
heap => { obj => MyObj->new(1..100) },
inline_states => {
_start => sub {
$_[KERNEL]->yield('do_task');
$_[KERNEL]->yield('tick');
},
do_task => sub {
$_[HEAP]{obj}->do_task and $_[KERNEL]->yield('do_task');
},
tick => sub {
return unless @{$_[HEAP]{obj}{files}};
print "tick\n";
$_[KERNEL]->delay(tick => 1);
},
},
);
もちろんdo_
マルチタスクからイベント駆動に
さて、
POE::Session->create(
heap => { obj => MyObj->new(1..100) },
inline_states => {
_start => sub { $_[KERNEL]->yield('tick') },
do_task => sub { $_[HEAP]{obj}->do_task },
tick => sub {
return unless @{$_[HEAP]{obj}{files}};
print "tick\n";
$_[KERNEL]->yield('do_task') if $_[HEAP]{counter}++ % 2;
$_[KERNEL]->delay(tick => 1);
},
},
);
ここでは単純にタイマーにあわせてタスクを実行しているだけですが、
豊富な関連モジュール
ただし、
たとえば、
もっと対象がはっきりしているのであれば、
クローラのようなものが要るなら、
先ほどの例ではセッションはひとつだけでしたが、
POEの公式サイトにはほかにも用途にあわせてさまざまなレシピが紹介されています。あまりにも多岐に渡るのでいちいち概要を紹介することはできませんが、
POEに対する批判
このように人気もメリットも大きいPOEですが、
マルチタスクやネットワーキングに対応したプログラミングそのもののむずかしさは脇におくとしても、
また、
もっとも、
POEのわかりづらさに対しても、
最近ではイベントループまわりのテストを改善しようという動きが進められていますし、
POEらしさからの脱却
2008年3月に晴れて正式リリース