今月の UNIX USER を読んでいたら、「Perl5.8 の新機能」で ithread (インタープリタ・スレッド) が使えるようになったとのこと。 これで「ruby ならスレッドが簡単に使えますよ」とか言われて悔しい思いをすることがなくなるかも! (謎)
...
まずは Perl 5.8.0 のインストール。既存の Perl を壊さないように、/usr/local/perl-5.8 以下にインストールする。
$ tar zxvf perl-5.8.0.tar.gz
$ cd perl-5.8.0
$ ./Configure -de -Duseithreads \
-Dcc=gcc_2_95_3 \
-Dprefix=/usr/local/perl-5.8 \
-Uinstallusrbinperl
$ make
$ make test
$ sudo make install
-Uinstallusrbinperl を指定しておかないと、既存の /usr/bin/perl が上書きされちゃうので注意。
$ /usr/local/perl-5.8/bin/perl -V:useithreads useithreads='define';
となれば、ithread が有効になってインストールされている。
...
さて、スレッドを使ったサンプルアプリということで、ab (Apache Bench)もどきを作ってみる。 ソースは こちら
#!/usr/local/perl-5.8/bin/perl
use strict;
use threads;
use threads::shared;
use LWP::Simple;
use Getopt::Std;
use Time::HiRes qw(tv_interval gettimeofday);
my %opts;
getopt('cnu', \%opts);
my $total_request : shared = 0; # $total_request は共有変数
my $success : shared = 0; # $success は共有変数
my $failed : shared = 0; # $failed は共有変数
sub request
{
my ($url) = @_;
while($total_request < $opts{n}){
if(get($url)){ # LWP::Simple:get でドキュメントを取得
lock($success); # $success をロック
$success++;
}else{
lock($failed);
$failed++;
}
{
lock($total_request);
$total_request++;
}
threads->yield; # CPUを開放、他のスレッドに使わせる
}
}
my $start_time = [gettimeofday]; # 開始時間設定
my @t;
foreach my $i(1 .. $opts{c}){ # -c で指定した数だけスレッドを起動
$t[$i] = threads->new(\&request, $opts{u});
}
foreach my $i(1 .. $opts{c}){ # すべてのスレッドが終了するまで待つ
$t[$i]->join;
}
my $end_time = tv_interval($start_time); # 実行時間を求める
my $request_per_second = sprintf("%.2f", $total_request / $end_time);
print <<END;
Concurrency Level: $opts{c}
Time taken for tests: $end_time seconds
Complete requests: $success
Failed requests: $failed
Requests per second: $request_per_second [#/sec] (mean)
END
で、これを
$ ./fake_ab.pl -c 10 -n 1000 -u http://aqua/
として実行する。 -c は同時実行スレッド(多重度)、-n は総リクエスト回数。
Concurrency Level: 10 Time taken for tests: 5.65637 seconds Complete requests: 1009 Failed requests: 0 Requests per second: 178.38 [#/sec] (mean)
このような出力を得る。ab の出力を、部分的にパクってみた。
...
取得する URL をいろいろ変えて、本家 ab との Requests per second を比較してみると、以下のとおり。
/ (ssi な HTML) ... (1) fake_ab.pl : 178.38 ab : 234.25 /cgi-bin/printenv.cgi (環境変数を表示するだけの mod_perl CGI) ... (2) fake_ab.pl : 105.95 ab : 121.58 /cgi-bin/index.cgi?rm=view (PostgreSQL に接続して数十レコードを閲覧する mod_perl CGI) ... (3) fake_ab.pl : 5.68 ab : 5.55
ab は C で書かれてコンパイルされた実行ファイルなので、動作が速い。 それに比べると Perl で実装された fake_ab.pl は遅いので、 単純な HTML を GET するような場合 (1) は、サーバの速度を最大限に引き出せていない。
が、比較的重い CGI (mod_perl) を実行するような場合 (3) なら、クライアントの速度差が無視できるので、 ほぼ同一の結果が得られる。
ふむ。なかなか簡単。
