Ho lavorato su diversi script Perl che elaborano file di dati a larghezza fissa di grandi dimensioni, estrapolando piccole sottostringhe da ogni record di dati. Avevo immaginato che la delega dell'estrazione delle sottostringhe alle chiamate ai metodi sarebbe costosa a causa del sovraccarico di copia del record di dati nell'array @_. Così ho eseguito quanto segue per confrontare (a) chiamata diretta a substr(), (b) chiamata di metodo passando il record di dati come stringa, e (c) chiamata di metodo passando il record di dati per riferimento.Si verifica una perdita di prestazioni durante la copia dei dati quando si passano gli argomenti alle subroutine di Perl?
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...
Come previsto, il metodo diretto è stato il più veloce. Tuttavia, sono stato sorpreso di non trovare penalità legate alla "copia di dati" che avevo immaginato. Anche quando aumentavo la larghezza del record in proporzioni stravaganti (ad esempio, un miliardo di caratteri), i benchmark in base al valore e al riferimento erano sostanzialmente gli stessi.
Sembra che quando si passano gli argomenti ai metodi, Perl non copia i dati. Immagino che questo abbia un senso dopo un'ulteriore riflessione sul potere di aliasing di @_. Gli argomenti vengono passati per riferimento, non per valore.
Tuttavia, è una forma limitata di passaggio per riferimento, poiché i riferimenti in @_ non possono essere assegnati direttamente a una variabile locale all'interno della subroutine. Tali assegnazioni comportano la copia dei dati, come illustrato dal secondo set di benchmark.
Sto comprendendo questo correttamente?
+1. Questa è la risposta corretta. –
@Igor Krivokon: corretto, sì, ma già indicato nella domanda, almeno implicitamente. Immagino "Sì, lo stai capendo correttamente."manca qualcosa come risposta. – ysth