これらのどれが安いですか?
$_ = 'abc123def';
s/\d+/$&*2/e;
say;
s/(\d+)/$1*2/e;
say;
これらのどれが安いですか?
$_ = 'abc123def';
s/\d+/$&*2/e;
say;
s/(\d+)/$1*2/e;
say;
エグゼクティブ サマリー: 代わりに 5.010 の /p を使用してください。のパフォーマンスは$&
、1 回の試合または交代ではほぼ同じですが、プログラム全体が影響を受ける可能性があります。減速は局所的ではなく、長期的です。
これは5.010のベンチマークです。そこにあるので、あなたが使用していると思われますsay
。5.010 には、同じように機能する変数を/p
提供する新しいフラグがありますが、一致演算子または置換演算子のインスタンスは 1 つだけであることに注意してください。${^MATCH}
$&
他のベンチマークと同様に、コントロールと比較してベースラインを設定するので、退屈なビットがどれだけの時間を費やしているかがわかります。また、このベンチマークには落とし穴があります。コード内で使用できない$&
か、すべての置換が影響を受けます。最初に$&
サブなしでベンチマークを実行します。
use 5.010;
use Benchmark qw(cmpthese);
cmpthese(1_000_000, {
'control' => sub { my $_ = 'abc123def'; s/\d+/246/ },
'control-e' => sub { my $_ = 'abc123def'; s/\d+/123*2/e; },
'/p' => sub { my $_ = 'abc123def'; s/\d+/${^MATCH}*2/pe },
# '$&' => sub { my $_ = 'abc123def'; s/\d+/$&*2/e },
'()' => sub { my $_ = 'abc123def'; s/(\d+)/$1*2/e },
});
Leopard とバニラの Perl 5.10 を実行している私の MacBook Air では:
Rate /p () control-e control
/p 70621/s -- -1% -58% -78%
() 71124/s 1% -- -58% -78%
control-e 168350/s 138% 137% -- -48%
control 322581/s 357% 354% 92% --
/e
笑いのために追加したオプションの大幅な速度低下に注意してください。
ここで、$&
ブランチのコメントを外します。すべてが遅くなることがわかりますが、/p
ここでは shihe のように見えます。
Rate () $& /p control-e control
() 68353/s -- -4% -7% -58% -74%
$& 70872/s 4% -- -3% -56% -73%
/p 73421/s 7% 4% -- -54% -72%
control-e 161290/s 136% 128% 120% -- -39%
control 262467/s 284% 270% 257% 63% --
これは奇妙なベンチマークです。サブを含めない場合control-e
、状況は異なって見えます。これは、ベンチマークの別の概念を示しています。ベンチマークは絶対的なものではなく、すべての操作が最終結果に影響します。この実行では、$&
わずかに高速に見えます。
Rate () /p $& control
() 69686/s -- -3% -3% -72%
/p 72098/s 3% -- -0% -71%
$& 72150/s 4% 0% -- -71%
control 251256/s 261% 248% 248% --
それで、control-e
もう一度実行したところ、結果が少し動きました。
Rate () /p $& control-e control
() 68306/s -- -3% -4% -55% -74%
/p 70175/s 3% -- -1% -54% -73%
$& 71023/s 4% 1% -- -53% -73%
control-e 151976/s 122% 117% 114% -- -41%
control 258398/s 278% 268% 264% 70% --
それぞれの速度の違いも印象的ではありません。約 7% 未満の値はそれほど重要ではありません。その差は、サブルーチンへの繰り返しの呼び出しによるエラーの蓄積によるものだからです (同じコードをそれ自体に対してベンチマークして、いつか試してみてください)。わずかな違いは、ベンチマーク インフラストラクチャに起因するものにすぎません。これらの数値を使用すると、各テクニックの速度は実質的に同じになります。ベンチマークを一度だけ実行することはできません。再現可能な結果が得られるかどうかを確認するには、数回実行する必要があります。
/p
が非常に遅く見えることに注意してください$&
。コントロールの速度低下にも注意してください。これが、ベンチマークが非常に危険な理由の 1 つです。結果が間違っている理由をよく考えないと、結果を簡単に誤解してしまう可能性があります (完全なスクリードについてはMastering Perlを参照してください。ここでは 1 章全体を説明しています)。
ただし、この単純でナイーブなベンチマークは、 の致命的な欠点を排除して$&
います。追加の一致を処理するようにベンチマークを変更してみましょう。まず、追加の一致演算子で約 1,000 文字をコピーする必要が$&
ある状況を構築した、効果のないベースライン:$&
use 5.010;
use Benchmark qw(cmpthese);
$main::long = ( 'a' x 1_000 ) . '123' . ( 'b' x 1_000 );
cmpthese(1_000_000, {
'control' => sub { my $_ = 'abc123def'; s/\d+/246/; $main::long =~ m/^a+123/; },
'control-e' => sub { my $_ = 'abc123def'; s/\d+/123*2/e; $main::long =~ m/^a+123/; },
'/p' => sub { my $_ = 'abc123def'; s/\d+/${^MATCH}*2/pe; $main::long =~ m/^a+123/; },
#'$&' => sub { my $_ = 'abc123def'; s/\d+/$&*2/e; $main::long =~ m/^a+123/;},
'()' => sub { my $_ = 'abc123def'; s/(\d+)/$1*2/e; $main::long =~ m/^a+123/; },
});
すべてが以前よりもはるかに遅くなりますが、それはより多くの作業を行うときに起こることであり、2 つの手法は互いのノイズの範囲内にあります。
Rate () /p control-e control
() 52826/s -- -4% -49% -63%
/p 54885/s 4% -- -47% -61%
control-e 103734/s 96% 89% -- -27%
control 141243/s 167% 157% 36% --
$&
ここで、サブのコメントを外します。
Rate () $& /p control-e control
() 50607/s -- -1% -3% -43% -59%
$& 50968/s 1% -- -2% -43% -58%
/p 52274/s 3% 3% -- -41% -57%
control-e 89206/s 76% 75% 71% -- -27%
control 122100/s 141% 140% 134% 37% --
その結果は非常に興味深いものです。現在/p
、 はまだ不正行為によって罰せられてい$&
ますが、誰もがかなり苦しんでいますが、わずかに高速です (まだノイズの範囲内ではあります)。
繰り返しますが、これらの結果には十分注意してください。$&
これは、すべてのスクリプトで同じ効果が得られるという意味ではありません。一致の数や特定の正規表現などによっては、速度低下が少なくなったり、遅くなったりするように見える場合があります。この、または任意のベンチマークが示しているのはアイデアであり、決定ではありません。このアイデアが特定の状況にどのように影響するかを理解する必要があります。
差出人perldoc perlvar
:
- $ MATCH
- $&
最後に成功したパターン一致と一致した文字列(a内に隠されている一致、
BLOCK
またはeval()
currentで囲まれている一致はカウントされませんBLOCK
)。(ニーモニック:一部のエディターでは&のようになります。)この変数は読み取り専用で、現在のに動的にスコープされBLOCK
ます。プログラム内のどこかでこの変数を使用すると、すべての正規表現の一致にかなりのパフォーマンスペナルティが課せられます。「バグ」を参照してください。
"@-"
交換についてはを参照してください。
この情報がドキュメントに都合よく記載されていなくても、自分で時間を計って調べることができます。
を使用した場合のパフォーマンスへの影響を把握する簡単な方法を次に示し$&
ます。まず、2 つのベンチマーク スクリプトを作成する必要があります。ほとんどのコードが共通しています。
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
use File::Spec::Functions qw( devnull );
open my $output, '>', devnull;
my $str = <<EO_LIPSUM;
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
occaecat cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
EO_LIPSUM
use Benchmark qw( timethese );
最初のベンチマークの追加
### benchmark with $MATCH
timethese -1, {
match_var => sub {
$str =~ /commodo/;
print $output $&;
$str =~ /^Lorem|ipsum/ and print $output 'yes';
}
}
2 番目のベンチマーク ファイルには、
timethese -1, {
capture => sub {
$str =~ /(commodo)/;
print $output $1;
$str =~ /^Lorem|ipsum/ and print $output 'yes';
}
}
それでは、これらのベンチマークを実行してみましょう (これらは別のファイルにある必要があります)。
ベンチマーク: 少なくとも 1 CPU 秒間キャプチャを実行しています... キャプチャ: 1 ウォールクロック秒 (1.05 usr + 0.00 sys = 1.05 CPU) @ 301485.20/s (n=315655)
ベンチマーク: 少なくとも 1 CPU 秒間 match_var を実行しています... match_var: 1 ウォールクロック秒 (1.22 usr + 0.02 sys = 1.23 CPU) @ 255591.09/s (n=315655)
つまり$&
、この場合、 を使用すると約 15% 速度が低下しました。$&
速度低下は、単純な正規表現一致への影響によるものです。なしで
$str =~ /^Lorem|ipsum/ and print $output 'yes';
のバージョンは、$&
実際にはより高速に実行されます。
use Benchmark;
そしてテスト。
一般的に - 本当に、本当に、それは問題ではありません。これらの操作を何十億回も行っていない限り。