PersistentPerl は Perlスクリプトをメモリに常駐させて起動時のオーバヘッドを軽減し、サーバ負荷やレスポンスを改善する。同じような機能の mod_perl ほどの効果はないようですが、導入が比較的楽そうなので、インストールから稼動までやってみました。
ちなみに、SpeedyCGI と PersistentPerl は同じもので、SpeedyCGI から PersistentPerl に名前が変わっただけと思っていいみたい。
試した環境
- Vine Linux4.2
- Kernel2.6.16
- Apache1.3.41
- Perl5.8.6
- PersistentPerl2.22
- gcc3.3.6
PersistentPerlインストール
CPANからインストール
testでコケたので、無理矢理。
途中で、mod_persistentperl をインストールするか問い合わせがありますが、デフォルト no なので、そのままエンター押してスルーです(mod_persistentperl は Apache のモジュールで、インストールするには apxs コマンドにパスが通ってないとダメらしいです。今回は CGI で PersistentPerl を使うだけなので、mod_persistentperl は特にインストールせず)。
CPANでだめならソースからコンパイルしてインストール。
# tar xvfz PersistentPerl-2.22.tar.gz
# cd PersistentPerl-2.22
# perl Makefile.PL
# make
# make test
# make install
OSによっては、バイナリがあったり、RPMがあったりするみたいですが、Vine Linuxでは見つからんかった(っつーか、あんま探してない)。
Perlスクリプトの編集
詳しいオプションなどは、後ほど公式ドキュメントを参照していただくとして、最低限、Perlスクリプトを PersistentPerl で利用するためには、以下の編集が必要になります。
スクリプト冒頭の Perlパスを以下のように書き換え。
なんと、たったこれだけでスクリプトがメモリに常駐してくれるようになり、サーバ負荷の軽減やレスポンス向上をもたらしてくれるのです。稼動の多いCGIスクリプトなんかでは重宝すると思います。
PersistentPerlのワナ
さて、すごく楽に導入できる PersistentPerl ですが、そこには当然ワナがあります。
Also, if you create global variables with ``my'', you shouldn't try to reference those variables from within a subroutine - you should pass them into the subroutine instead. Or better yet just declare global variables with ``use vars'' instead of ``my'' to avoid the problem altogether.
スクリプトがメモリに常駐して実行されるため、グローバル変数が破棄されないというルールがあり、これはスクリプトの書き方によってはひっかかります。特に、my によって初期化しているつもりのグローバル変数を、サブルーチンに明示的に渡さず使用している場合、おかしなことになります。
例えば、以下のコードはクエリーを表示するだけですが、グローバル変数($q)をサブルーチンに明示的に受け渡さず、サブルーチン(put_q)内で直接参照して表示しています。
[test.cgi]
use strict;
my $q = $ENV{'QUERY_STRING'}; # $q を my 宣言
&put_q;
exit;
sub put_q {
print "Content-Type: text/html\n\n";
print $q; # グローバルの $q を参照表示
}
これを、CGIとして実行すると、1回目は望み通りの出力となりますが、2回目からはクエリーに何を渡しても1回目の出力から変化がなくなります。
[1回目の実行]
[2回目の実行]
use strict; も宣言して通っているのに、と不可思議な気がするかもしれません。
これは、グローバル変数として my で定義されている $q がサブルーチン内で参照されるとき、1回目の実行で作成された $q を参照していることから起こります。3回目以降実行されてもずっと1回目のものとなります(PersistentPerlが再起動されると再定義されますが、メモリに常駐している間は同じ)。
この現象は以下のように、明示的に変数を受け渡すことで回避できます。
use strict;
my $q = $ENV{'QUERY_STRING'};
&put_q($q);
sub put_q {
my $str = shift;
print "Content-Type: text/html\n\n";
print $str;
}
または、our(use vars qw($hoge);)で宣言することでも回避できます。
use strict;
our $q = $ENV{'QUERY_STRING'};
&put_q;
sub put_q {
print "Content-Type: text/html\n\n";
print $q;
}
都度 実行するだけのCGIを書いているうちは、なんとか動くので気付きにくいですが、そういうことらしいです。
プログラミングの作法として覚えておこうと思う。
