私は大規模な固定幅のデータファイルを処理するいくつかのPerlスクリプトに取り組んでおり、各データレコードから小さな部分文字列を抽出しています。データレコードを@_配列にコピーするオーバーヘッドのため、メソッド呼び出しに部分文字列の抽出を委任するのはコストがかかると想像していました。そこで、(a)substr()への直接呼び出し、(b)データレコードを文字列として渡すメソッド呼び出し、(c)データレコードを参照渡しするメソッド呼び出しを比較するために以下を実行しました。Perlサブルーチンに引数を渡す際に、データコピーのパフォーマンスが低下しますか?
use strict;
use warnings;
use Benchmark qw(timethese);
my $RECORD = '0' x 50000;
my $direct = sub { my $v = substr($RECORD, $_, 1) for 0..999 };
my $byVal = sub { my $v = ByVal ($RECORD, $_) for 0..999 };
my $byRef = sub { my $v = ByRef (\$RECORD, $_) for 0..999 };
sub ByVal { return substr( $_[0], $_[1], 1) }
sub ByRef { return substr(${$_[0]}, $_[1], 1) }
timethese(10000, {
direct => $direct,
byVal => $byVal,
byRef => $byRef,
});
my $byVal2loc = sub { my $v = ByVal2loc($RECORD, $_) for 0..999 };
my $byRef2loc = sub { my $v = ByRef2loc(\$RECORD, $_) for 0..999 };
sub ByVal2loc { my $arg = shift; return substr( $arg, $_[0], 1) }
sub ByRef2loc { my $arg = shift; return substr($$arg, $_[0], 1) }
timethese($ARGV[0], {
byVal2loc => $byVal2loc,
byRef2loc => $byRef2loc,
});
# Produces this output:
Benchmark: timing 10000 iterations of byRef, byVal, direct...
byRef: 19 wallclock secs...
byVal: 15 wallclock secs...
direct: 4 wallclock secs...
Benchmark: timing 10000 iterations of byRef2loc, byVal2loc...
byRef2loc: 21 wallclock secs...
byVal2loc: 119 wallclock secs...
予想通り、直接的な方法が最も速かった。しかし、私が想像していた「データのコピー」に関連するペナルティはないことに驚きました。たとえ私がレコードの幅を異国的な割合(例えば10億文字)に増やしたとしても、バイ・バリューとバイ・リファレンスのベンチマークは基本的に同じでした。
引数をメソッドに渡すと、Perlはデータをコピーしないようです。私は、@ _のエイリアシング能力についてのさらなる反映が理にかなっていると思います。引数は値ではなく参照渡しに渡されます。
しかし、@_の参照をサブルーチン内のローカル変数に直接割り当てることができないため、これは参照渡しの制限された形式です。このような割り当ては、第2セットのベンチマークによって示されるように、データコピーをもたらす。
これを正しく理解していますか?
+1を。これは正解です。 –
@Igor Krivokon:正解ですが、質問には少なくとも暗黙のうちにすでに述べられています。私は推測する "はい、これを正しく理解している。"答えとして何かが欠けている。 – ysth