Frage

Welches davon ist günstiger?

$_ = 'abc123def';

s/\d+/$&*2/e;
say;

s/(\d+)/$1*2/e;
say;
War es hilfreich?

Lösung

Zusammenfassung : 5.010 / die p stattdessen verwenden. Die Leistung von $& ist etwa das gleiche für ein Einzelspiel oder Substitution, sondern das gesamte Programm können daran leiden. Es ist Verlangsamung Langstrecken ist, nicht lokal.


Hier ist ein Benchmark mit 5.010, die ich vermute, Sie verwenden, da Sie dort say haben. Beachten Sie, dass 5.010 eine neue /p Flagge hat, die eine ${^MATCH} Variable liefert, die wie $& wirkt aber nur eine Instanz des Spiels oder Substitution Operators.

Wie bei jedem Benchmark vergleiche ich mit einer Kontrolle der Grundlinie zu setzen, damit ich weiß, wie viel Zeit die langweiligen Bits in Anspruch nehmen. Außerdem hat dieser Benchmark eine Falle: Sie können nicht $& im Code oder jede Substitution leidet verwenden. Zunächst läuft die Benchmark ohne $& sub:

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 },
});

Auf meinem MacBook Air mit Leopard und einem Vanille Perl 5.10:

              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%        --

Beachten Sie die große Verlangsamung der /e Option, die ich für kichert gerade hinzugefügt haben.

Jetzt werde ich den $& Zweig Kommentar-, und ich sehe, dass alles langsamer, obwohl /p scheint zu Shihe hier:

              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%        --

Dies ist eine ungeradee Benchmark. Wenn ich die control-e Unter nicht enthalten, sieht die Situation anders aus, was ein anderes Konzept des Benchmarking zeigt: es ist nicht absolut und alles, was Sie Fragen in den endgültigen Ergebnissen zu tun. In diesem Durchlauf sieht $& etwas schneller:

            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%      --

Also, ich lief es mit control-e wieder, und die Ergebnisse bewegen sich ein wenig:

              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%        --

Die Geschwindigkeitsunterschiede in den einzelnen sind entweder nicht beeindruckend. Alles, was unter etwa 7% ist nicht so wichtig, da die Differenz der Anhäufung von Fehlern durch die wiederholten Aufforderungen an die Unter kommt (versuchen Sie es irgendwann durch den gleichen Code Benchmarking gegen sich selbst). Die geringen Unterschiede sehen Sie kommen nur aus der Benchmarking-Infrastruktur. Mit diesen Zahlen ist jede Technik praktisch gleich speedwise. Sie können Ihre Benchmark nicht nur einmal ausgeführt werden. Sie haben es mehrmals ausführen, um zu sehen, ob Sie wiederholbare Ergebnisse zu erhalten.

Beachten Sie, dass, obwohl die /p sehr geringfügig langsamer aussieht, ist es auch langsamer, weil $& Betrüger von jedem vermasselt. Beachten Sie die Verlangsamung der zu Kontrolle. Dies ist einer der Gründe dafür, dass Benchmarking so gefährlich ist. Sie können sich einfach mit den Ergebnissen die Irre führen, wenn Sie nicht denken, hart darüber, warum sie falsch sind (die vollständige Estrich in Mastering Perl , wo ich ein ganzes Kapitel dieses widmen.)

Diese einfache und naive Benchmark schließt den Killer disfeature von $&, though. Lassen Sie sich den Maßstab ändert ein zusätzliches Spiel zu behandeln. Zunächst wird die Basislinie ohne $& Effekte, wo ich eine Situation aufgebaut habe, wo $& hätten etwa 1.000 Zeichen in einem weiteren Match-Operator kopieren:

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/; },
});

Alles ist viel langsamer als zuvor, aber das ist, was passiert, wenn Sie mehr Arbeit zu tun, und wieder die beiden Techniken sind in jedem der anderen Lärm:

              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%        --

Nun, ich Kommentar- der $& sub:

              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%        --

Das Ergebnis ist sehr interessant. Jetzt /p, noch durch den Betrug $& bestraft, ist etwas schneller (obwohl immer noch im Rauschen), obwohl jeder leidet erheblich.

Auch hier sehr vorsichtig sein mit diesen Ergebnissen. Dies bedeutet nicht, dass für jedes Skript, $& die gleiche Wirkung hat. Sie könnten weniger eine Verlangsamung scheinen, oder mehr davon, abhängig von der Anzahl der Spiele, die besonderen Regexes, und so weiter. Was diese oder eine beliebige Benchmark zeigt, ist eine Idee, keine Entscheidung. Sie haben noch ho, um herauszufinden,w diese Idee wirkt sich auf Ihre besondere Situation.

Andere Tipps

perldoc perlvar :

  
      
  • $ MATCH
  •   
  • $ &
  •   
     

Die Zeichenfolge durch den letzten erfolgreichen Mustervergleich angepasst (keine Streichhölzer Zählen innerhalb eines BLOCK oder eval() von dem aktuellen BLOCK eingeschlossen versteckt). . (Mnemonic. Wie & in einigen Editoren) Diese Variable ist schreibgeschützt und dynamisch an den aktuellen BLOCK scoped

     

Die Verwendung dieser Variablen überall in einem Programm erlegt eine erhebliche Leistungseinbuße auf alle regulären Ausdruck übereinstimmt. Siehe "BUGS" .

     

Siehe "@-" für einen Ersatz.

Auch wenn diese Informationen nicht in geeigneter Weise in der Dokumentation, so könnte man es noch selbst Zeit und erfahren.

Hier ist eine einfache Möglichkeit, eine Vorstellung von den Performance-Auswirkungen der Verwendung von $& zu bekommen. Zunächst einmal müssen Sie zwei Benchmark-Skripte erstellen. Sie werden die meisten der Code gemeinsam haben:

#!/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 );

Für die erste Benchmark hinzufügen

### benchmark with $MATCH

timethese -1, {
    match_var => sub {
        $str =~ /commodo/;
        print $output $&;
        $str =~ /^Lorem|ipsum/ and print $output 'yes';
    }
}

und für die zweite Benchmark-Datei verwenden

timethese -1, {
    capture => sub {
        $str =~ /(commodo)/;
        print $output $1;
        $str =~ /^Lorem|ipsum/ and print $output 'yes';
    }
}

Nun wollen wir diese Benchmarks laufen (sie muss in separaten Dateien sein):

Benchmark: running capture for at least 1 CPU seconds...
   capture:  1 wallclock secs ( 1.05 usr +  0.00 sys =  1.05 CPU) @ 301485.20/s
(n=315655)
Benchmark: running match_var for at least 1 CPU seconds...
 match_var:  1 wallclock secs ( 1.22 usr +  0.02 sys =  1.23 CPU) @ 255591.09/s
(n=315655)

Das heißt, verursacht mit $& eine Verlangsamung von etwa 15% in diesem Fall. Die Abschwächung ist aufgrund der Auswirkungen von $& auf dem einfachen regulären Ausdruck. Ohne die

$str =~ /^Lorem|ipsum/ and print $output 'yes';

Zeile, die Version mit $& führt tatsächlich schneller.

use Benchmark;

und Test.

Generell - wirklich, wirklich, spielt es keine Rolle. Es sei denn, Sie Milliarden von diesen Operationen zu tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top