うまいぼうぶろぐ

linuxとhttpdとperlのメモ

PersistentPerl(or mod_perlとか)でのmyとourとサブルーチンの引数に渡した場合の挙動の違いが良くわからない

グローバルが実行の間で保持されます。例えば永続的なデータベース・ハンドルを保つということではいいことかもしれませんが、あなたのコードがそれらが未定義であることを想定していればよくありません。

また、グローバル変数を"my"で作成するならば、サブルーチンの中からそれらの変数を参照しようとするべきではありません - その代わりにそれらをサブルーチンに渡すべきです。あるいは完全に問題をさけるために、単にmyの代わりに"use vars"でグローバル変数を宣言したほうが、まだましです。

ここに、この問題についての素晴らしい説明があります - これはmod_perlについてですが同じことがpersistentperlにも当てはまります:

http://perl.apache.org/faq/mod_perl_cgi.html#Variables_retain_their_value_fro

全てが失敗するのであれば、MaxRunsを1に設定することにより常駐を無効にすることができます。これが通常のperlに比較しての唯一の利点は、speedyがスクリプトを事前にコンパイルすることにあります。

documentにあるように、サブルーチンの外で宣言されたmy変数を、サブルーチンが直接参照してると初回に実行された際に値が変わらずにちょっと問題が起きる? ourが宣言するか、myで宣言した変数をサブルーチンの引数に渡している場合は問題ない。

ただ、何故そうなるのかがわからない。特に、同じmyで宣言した変数を、サブルーチンの引数に渡した場合と、サブルーチンから直接 外の変数を参照した場合の違いが。

テスト

  • randomな数値を$foo, $bar, $bazに代入。bazだけourで宣言。
  • サブルーチン _fooはサブルーチンの外で宣言した$fooを参照
  • サブルーチン _barは引数に渡された$barを参照
  • サブルーチン _bazはサブルーチンの外で宣言した$bazを参照

hoge.cgi

#!/usr/bin/perperl 
use strict;
print "Content-Type: text/html\n\n";

my  $foo  = sprintf("%0.10f", rand(1));
my  $bar  = sprintf("%0.10f", rand(1));
our $baz  = sprintf("%0.10f", rand(1));

print "main: my  foo $foo ", \$foo, "\n";
_foo();

print "main: my  bar $bar ", \$bar, "\n";
_bar($bar);

print "main: our baz $baz ", \$baz, "\n";
_baz();

exit;

sub _foo {
  print "sub : my  foo $foo ", \$foo, "\n";
}

sub _bar {
  my $bar = shift;
  print "sub : my  bar $bar ", \$bar, "\n";
}

sub _baz {
  print "sub : our baz $baz ", \$baz, "\n";
}

cgi経由(cliでもいいけど)で複数回アクセス。

$ curl http://localhost/perl/hoge.cgi
main: my  foo 0.8088552596 SCALAR(0x800c84)
sub : my  foo 0.8088552596 SCALAR(0x800c84)
main: my  bar 0.3774023467 SCALAR(0x800c78)
sub : my  bar 0.3774023467 SCALAR(0x813154)
main: our baz 0.3769106325 SCALAR(0x800fa8)
sub : our baz 0.3769106325 SCALAR(0x800fa8)
$ curl http://localhost/perl/hoge.cgi
main: my  foo 0.1496637709 SCALAR(0x8002a0)
sub : my  foo 0.8088552596 SCALAR(0x800c84)
main: my  bar 0.9524464525 SCALAR(0x800c78)
sub : my  bar 0.9524464525 SCALAR(0x81328c)
main: our baz 0.1257975709 SCALAR(0x800fa8)
sub : our baz 0.1257975709 SCALAR(0x800fa8)
$ curl http://localhost/perl/hoge.cgi
main: my  foo 0.2689451591 SCALAR(0x8002a0)
sub : my  foo 0.8088552596 SCALAR(0x800c84)
main: my  bar 0.6815530705 SCALAR(0x800c78)
sub : my  bar 0.6815530705 SCALAR(0x813310)
main: our baz 0.3494160401 SCALAR(0x800fa8)
sub : our baz 0.3494160401 SCALAR(0x800fa8)
  1. _fooが参照している$fooのリファレンスも値も初回実行時のまま変わらない
  2. _barの中で宣言している$barは毎回リファレンスも値が変更されてる # これは当然な気がする
  3. _bazが参照している$bazの値はmainで宣言している$bazと同じで、毎回変更されてる

mainの$fooと_fooが参照している$fooって当然同じだと思ってたんだけど、なんでここが違っているのだろう。perperlとかが常駐している仕組みがわかってないから理解できないだけなのかなー。