もうずいぶん前からCoroを使いたくて使いたくてしょうがなかったのだが、やっときたよ。Flickr APIを叩いて、非同期I/OしながらCoroで写真の情報をダウンロードするよ!

まず某sukebeさん作のWebService::Simpleを使ってみるよ(本当に使ったコードは違うフレームワーク用にいろいろついてたので、あまり利便性とか考えずに説明用のコードだけ書きだします)
package MyFlickrModel; use strict; use WebService::Simple; my $webservice = WebService::Simple->new( \%必要な引数 ); # 写真のIDを渡すとinfo, context, sizes, permsを全部ひっぱってくる sub find_photo { my $class = shift; my $photo_id = shift; my %photo; foreach my $type qw(info context sizes perms) { my $method = "find_photo_$type"; $photo{$type} = $class->$method($photo_id); } return \%photo; } # infoをひっぱってくる sub find_photo_info { my ($class, $id) = @_; my $response = $webservice->get( { method => "flickr.photos.getInfo", photo_id => $id } ); # エラーチェックとかはしょってます return $response->parse_xml; } # あと同じようにcontext, sizes, perms用の関数を書く # で、よびだす MyFlickrModel->find_photo( $photo_id );
でもこれだと写真1個につき都合4回、順番にFlickr APIを叩かなくちゃいけないね。そんなに待ちたくないんだな。非同期にしたいじゃん?で、ここでCoroですよ
Coroはcoroutineの実装をPerl5上でするわけですな。で、ちょっとハックだけれども、LWP::UserAgent系のモジュールの中身も適当にいじってくれるモジュールも用意してくれている。なのでそこらへんをまず追加:
use Coro; use Coro::Event; use Coro::LWP; use WebService::Simple; # 必ずCoro::LWPのあとに
で、先ほどのfind_photoをちょっと書き換える。ほんとにちょっとですよ?
sub find_photo { my $class = shift; my $photo_id = shift; my %photo; my @coros; # Coroを取っておく foreach my $type qw(info context sizes perms) { push @coros, async { # ここを別Coroに切り分ける my $method = "find_photo_$type"; $photo{$type} = $class->$method($photo_id); }; } $_->join for @coros; # Coroが終了するのを待つ return \%photo; }
以上! これだけで、10個の写真を検索→その後find_photo()で詳細を取得、というのが単純に17秒弱から5秒強に減った。Coroすげぇ

ちなみに同じことをしつつ、Cache::Memcached::libmemcachedでキャッシュすると0.2秒で終わるよ!