値、特に大きな配列など、たくさんのデータを渡すときには、「リファレンス」というものを用いると良いらしい。・・・ということで、どのくらい有効なのか?と思ってやってみた。
一応書いておきますが、サンプルで実行できるのは、下の方に書いてある「リファレンスの使用法」みたいなものです。ベンチマークとは関係ありませんので、適当に実行してください。
まず、基準となる配列「$cnt個」に乱数「rand」を格納した。それを「my」変数に書き込むサブルーチンを作って「$count」回「Benchmark」してみました。(基本的な書式)
|
$count の値 |
$cnt の値 |
リファレンス不使用 |
リファレンス使用 |
Type1 |
1000 |
100 |
7.14 |
2.48 |
Type2 |
1000 |
10 |
1.87 |
1.26 |
Type3 |
10000 |
1 |
12.97 |
11.58 |
Type4 |
100 |
1000 |
5.77 |
1.32 |
この計測が正しい方法なら、配列が大きければ大きいほど、「リファレンス」を使ったほうが処理が速いようだ。
ちなみに、「print」に関係する部分を削除すると、より明らかに差が出た。
ただ、「リファレンス」を参照する(本には「デリファレンス」と書いてあった)には、配列なら「@」を、ハッシュなら「%」を「リファレンス変数」の前につける必要がある。実は、これが結構面倒だったりする。
また、個別に参照するには通常と同じように「$」を頭につける。つまり「$$array[0]」や「$$hash{num}」のように・・・。で、なぜか知らないけど、配列の場合だけは「@$array[0]」でも参照できる。普通の配列でも「@a[0]」で参照できる(この辺はおそらくPerl5のみ)。このおかげで「@」が「"(ダブルクォート)」の中では展開されるようになり、文字として表示するには「エスケープ」しないといけなくなったんだろう。
この他に「矢印記法」というものもあり、例えば「$$array[0](または@$array[0])」の場合は「$array->[0]」と記述する事もできる。ハッシュなら「$$hash{num}」が「$hash->{num}」といった具合。ややこしいけど、なかなか面白いことを考える。
この「リファレンス」というやつは、サブルーチンに対しても作る事ができるし、さらに、その「リファレンスされたサブルーチン」が、それぞれ違う値を返したり・・・と、なかなか奥が深い。理解するのは結構時間がかかりそうだ。
ソースコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#!/usr/bin/perl
#BEGIN{
# print "Content-type: text/plainnn";
# open(STDERR, ">&STDOUT");
# $|=1;
#}
%h = (
'num1' => 1,
'num2' => 2,
);
@a = (1,2);
$hash = %h;
$array = @a;
print <<EOM;
Content-type: text/plain
$h{num1} = $h{num1}
$$hash{num1} = $$hash{num1}
%$hash{num1} = %$hash{num1}
$hash->{num1} = $hash->{num1}
$a[0] = $a[0]
@a[0] = @a[0]
$$array[0] = $$array[0]
@$array[0] = @$array[0]
$array->[0] = $array->[0]
EOM
|
ベンチマーク用ソースコード
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
#!/usr/bin/perl
BEGIN{
print "Content-type: text/plainnn";
open(STDERR, ">&STDOUT");
$|=1;
}
use Benchmark;
$count = 1000;
$cnt = 100;
$dat1 = "reftest1.txt";
$dat2 = "reftest2.txt";
srand;
for(0 .. $cnt){
@nums[$_] = rand;
}
open(OUT, "> $dat1");
close(OUT);
open(OUT, "> $dat2");
close(OUT);
sleep 1;
@t = timethese($count, {
'Refuse' => '&use_ref;',
'RefNouse' => '&nouse_ref;',
});
exit(0);
sub use_ref{
my $r_nums;
$r_nums = @nums;
open(OUT, ">> $dat1");
foreach(@$r_nums){
print OUT "$_\n";
}
close(OUT);
}
sub nouse_ref{
my @n_nums;
@n_nums = @nums;
open(OUT, ">> $dat2");
foreach(@n_nums){
print OUT "$_\n";
}
close(OUT);
}
|