Ich habe an mehreren Perl-Skripten gearbeitet, die große Datendateien mit fester Breite verarbeiten und kleine Teilstrings aus jedem Datensatz extrahieren. Ich hatte mir vorgestellt, dass das Delegieren des Extrahierens von Teilstrings an Methodenaufrufe wegen des Overheads beim Kopieren des Datensatzes in das @_-Array kostspielig sein würde. Also habe ich die folgenden Tests durchgeführt, um (a) den direkten Aufruf von substr(), (b) den Methodenaufruf, der den Datensatz als String übergibt, und (c) den Methodenaufruf, der den Datensatz per Referenz übergibt, zu vergleichen.
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...
Wie erwartet, war die direkte Methode die schnellste. Allerdings war ich überrascht, dass es keine Nachteile durch das "Kopieren von Daten" gab, wie ich es mir vorgestellt hatte. Selbst als ich die Breite des Datensatzes auf haarsträubende Größenordnungen erhöhte (z. B. eine Milliarde Zeichen), waren die Benchmarks für die By-Value- und die By-Reference-Methode im Wesentlichen gleich.
Es scheint, dass Perl bei der Übergabe von Argumenten an Methoden keine Daten kopiert. Ich denke, das macht Sinn, wenn man weiter über die Aliasing-Kraft von @_ nachdenkt. Die Argumente werden per Referenz übergeben, nicht per Wert.
Es handelt sich jedoch um eine eingeschränkte Form der Weitergabe von Verweisen, da die Verweise in @_ nicht direkt einer lokalen Variablen innerhalb des Unterprogramms zugewiesen werden können. Solche Zuweisungen führen zu einem Kopieren von Daten, wie die zweite Reihe von Benchmarks zeigt.
Verstehe ich das richtig?