読者です 読者をやめる 読者になる 読者になる

はちゅにっき

こっちのブログはまったり更新

FurlX::Coro を使ってみたかった

節電対応で休日が日・月になった hatyuki です。ということで、明日がおやすみ!

「DB から引っ張ってきた 5,000 件くらいの URL が、全部 HTTP Status Code 200 を返してくるか調べたいんだけど。」
という、なさそうでやっぱない依頼をうけたのでささっと書いてみることに。

ぱっと思いついたのはこんな感じ。

use strict;
use warnings;
use Furl;
use My::Util qw/ db /;
use Test::More;

my $furl = Furl->new;
my $itr  = db->search('tables');
while (my $row = $itr->next) {
    my $res = $furl->head($row->url);
    is $res->code, 200, $row->url;
}

done_testing;

で実行してみたら Furl は確かに早いんだけど、さすがにチェックする URL の数が多すぎてちょっと時間かかりすぎる感じ。
そーいえば id:gfx さんが

Released FurlX-Coro!
http://d.hatena.ne.jp/gfx/20110625/1308978199

なんて記事を書いていたなぁ。と思い出したので FurlX::Coro を使ってみることに。
参照先の記事に書いてある内容そのままですが、こんな感じになりました。

use strict;
use warnings;
use Coro;
use FurlX::Coro;
use Test::More;
use My::Util qw/ db /;

my $itr = db->search('tables');
my @coros;

while (my $row = $itr->next) {
    push @coros, async {
        my $furl = FurlX::Coro->new;
        my $res  = $furl->head($row->url);
        is $res->code, 200, $row->url;
    };
}

$_->joins for @coros;

done_testing;

Furl の代わりに Coro と FurlX::Coro を use して、あとは Coro っぽい書き方をちょっと加えるだけなので、すごく簡単ですね。
で、実行してみたら超はや、、、あれ?
「おい!Load Average が 300 超えてるぞ!」
あー。そういえば URL って全部同一ドメインだった!
ということで Coro::Semaphore も使うことに。
こんな感じ。

use strict;
use warnings;
use Coro;
use Coro::Semaphore;
use FurlX::Coro;
use Test::More;
use My::Util qw/ db /;

my $itr = db->search('tables');
my @coros;

my $semaphore = Coro::Semaphore->new(10); # 10 並列まで
while (my $row = $itr->next) {
    push @coros, async {
        my $guard = $semaphore->guard;
        my $furl = FurlX::Coro->new;
        my $res  = $furl->head($row->url);
        is $res->code, 200, $row->url;
    };
}

$_->joins for @coros;

done_testing;

今度こそ、早く安全 (?) に HTTP Status Code を確認することができました。
やったね!

えっ?確認すべき URL があと 100,000 あるの?なんか間違ってない。。。?
そんな週末。

結論

  • FurlX::Coro すごく便利
  • 同時接続数を制限しないと、鬼の形相で人が飛んで来る
  • Coro で同時実行数を制御するには Coro::Semaphore が便利
  • 外部のサーバには絶対にやっちゃだめ
  • PHP でも Coro したいんだけど。。。


むしろ PHP を Coro したい。