Async::Selector v1.011をリリース

PerlモジュールAsync::Selector v1.011をリリースした。

元々v0.02をリリース済みだったんだけど、ちょっとPODを修正・加筆しようと思ったらいろいろAPIでイケてないところがボロボロ出てきて結局大改造になってしまった。
けど、既存のAPI仕様に対する互換性は維持できたと思う。

Async::SelectorはEvent::Notifyと同じような、Pub-SubパターンにおけるPublisherとSubscriberの待ち合わせのポイントになるオブジェクトなんだけど、以下のような特徴を持っている。

  • プログラム中の何らかの「リソース」の監視に特化
  • Subscriberはそれぞれ欲しいリソースが満たすべき「条件」を指定でき、リソースが「条件」を満たした場合にコールバックが起動される
  • Subscription要求時に既にリソースが「条件」を満たしている場合、即座にコールバックが起動される (レベルトリガー型)

ここで言う「リソース」とは抽象的な概念であって、CPUとかファイルとかに限られないことに注意されたい。

イメージとしては、select(2)システムコールを一般化・非同期化したようなものだと思っている。
select(2)システムコールの場合、「リソース」はファイルデスクリプタで、「条件」は読み込み可能・書き込み可能・例外発生のいずれか、ということになる。


SYNOPSISに書いた使用例はこんな感じ。

use Async::Selector;

my $selector = Async::Selector->new();

## Register resource
my $resource = "some text.";  ## 10 bytes

$selector->register(resource_A => sub {
    ## If length of $resource is more than or equal to $threshold bytes, provide it.
    my $threshold = shift;
    return length($resource) >= $threshold ? $resource : undef;
});


## Watch the resource with a callback.
$selector->watch(
    resource_A => 20,  ## When the resource gets more than or equal to 20 bytes...
    sub {              ## ... execute this callback.
        my ($watcher, %resource) = @_;
        print "$resource{resource_A}\n";
        $watcher->cancel();
    }
);


## Append data to the resource
$resource .= "data";  ## 14 bytes
$selector->trigger('resource_A'); ## Nothing happens

$resource .= "more data";  ## 23 bytes
$selector->trigger('resource_A'); ## The callback prints 'some text.datamore data'


ここでいう「リソース」は変数$resourceに格納された単なる文字列。このリソースをregisterメソッドで$selectorオブジェクトに登録する際、$resourceのバイト数がSubscriberの与える$threshold以上の時のみ、$resourceの内容を提供するようにしている。

次に、watchメソッドでリソースを監視するが、ここでthresholdは20バイトを指定する。$resourceが20バイト以上になったとき、watchメソッドで指定したコールバックが実行され、$resourceの内容が表示される。

その後、$resourceの中身を変更したらその都度triggerメソッドで$selectorオブジェクトに変更を通知してやればいい。最初、文字列"data"を加えた時はまだ14バイトしかないのでコールバックは実行されないが、さらに文字列を追加して23バイトになった時、コールバックが実行される。

Event::Notifyなどを使ってSubscriber側でイベントをフィルタリングすればそれでいい気もするけど、Async::Selectorではwatchメソッド実行時にリソースが条件を満たしていた場合、即座にコールバックを実行するのが特徴だと思う。

Async::Selectorを使って、アプリケーションの持つデータをComet(long-polling)やWebSocketを使ってWebブラウザに配信する例も書いてみた。