今月の 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) なら、クライアントの速度差が無視できるので、 ほぼ同一の結果が得られる。
ふむ。なかなか簡単。