これについていくつかのデータを取得しましょう。みんなのテクニックをベンチマークしました...
#!/usr/bin/env perl
sub flag_in_loop {
my $file = shift;
open my $fh, $file;
my $first = 1;
while(<$fh>) {
if( $first ) {
$first = 0;
}
else {
my $line = $_;
}
}
return;
}
sub strip_before_loop {
my $file = shift;
open my $fh, $file;
my $header = <$fh>;
while(<$fh>) {
my $line = $_;
}
return;
}
sub line_number_in_loop {
my $file = shift;
open my $fh, $file;
while(<$fh>) {
next if $. < 2;
my $line = $_;
}
return;
}
sub inc_in_loop {
my $file = shift;
open my $fh, $file;
my $first;
while(<$fh>) {
$first++ or next;
my $line = $_;
}
return;
}
sub slurp_to_array {
my $file = shift;
open my $fh, $file;
my @array = <$fh>;
shift @array;
return;
}
my $Test_File = "/usr/share/dict/words";
print `wc $Test_File`;
use Benchmark;
timethese shift || -10, {
flag_in_loop => sub { flag_in_loop($Test_File); },
strip_before_loop => sub { strip_before_loop($Test_File); },
line_number_in_loop => sub { line_number_in_loop($Test_File); },
inc_in_loop => sub { inc_in_loop($Test_File); },
slurp_to_array => sub { slurp_to_array($Test_File); },
};
これは Benchmark.pm の調整能力を超えた力の影響を受ける可能性がある I/O であるため、それらを数回実行し、同じ結果が得られることを確認しました。
/usr/share/dict/words
は、約 240k の非常に短い行を含む 2.4 MB のファイルです。行を処理していないため、行の長さは問題になりません。
テクニックの違いを強調するために、各ルーチンでほんの少しの作業しか行いませんでした。ファイルの読み取り方法を変更することで、パフォーマンスがどれだけ向上または低下するかについて、現実的な上限を作成するために、いくつかの作業を行いたいと考えました。
SSDを搭載したラップトップでこれを行いましたが、それでもラップトップです。I/O 速度が向上するにつれて、CPU 時間はより重要になります。高速 I/O を備えたマシンでは、テクニックがさらに重要になります。
各ルーチンが 1 秒間にファイルを読み取る回数は次のとおりです。
slurp_to_array: 4.5/s
line_number_in_loop: 13.0/s
inc_in_loop: 15.5/s
flag_in_loop: 15.8/s
strip_before_loop: 19.9/s
私はそれmy @array = <$fh>
が非常に遅いことを知ってショックを受けました。すべての作業が perl インタープリター内で行われていることを考えると、これが最速だと思っていたでしょう。ただし、すべての行を保持するためにメモリを割り当てる唯一のものであり、おそらくパフォーマンスの遅れを説明しています。
使用$.
は別の驚きです。おそらくそれは、魔法のグローバルにアクセスするためのコストか、数値比較を行うためのコストです。
そして、アルゴリズム分析で予測されたように、ヘッダー チェック コードをループの外側に配置するのが最も高速です。しかし、それほどではありません。次の 2 つの最速を使用している場合は、おそらく心配するほどではありません。