2010-07-23 9 views
6

Qual è la differenza, dal POV dell'interprete, tra le seguenti i seguenti programmi:Perl: Perché è più lento dichiarare variabili (mie) all'interno di un ciclo?

#!/usr/bin/perl -w 

use strict; 

for (1..10000000) { 
    my $jimmy = $_**2; 
} 

e

#!/usr/bin/perl -w 

use strict; 

my $jimmy; 
for (1..10000000) { 
    $jimmy = $_**2; 
} 

rapporti di "tempo" per il primo programma:

real 0m1.519s 
user 0m1.513s 
sys  0m0.004s 

e per il secondo:

real 0m1.023s 
user 0m1.012s 
sys  0m0.002s 
+2

In aggiunta alle risposte di Robert Greiner, i due posizionamenti di 'my' nel codice sono semanticamente diversi che potrebbero essere importanti nei programmi non giocattolo. – msw

+4

Ricorda che, solo perché puoi ottimizzare un pezzo di codice, non significa che dovresti. Esegui il profilo dell'intera applicazione e verifica se il bit di codice che stai tentando di ottimizzare è un grosso pezzo del tuo tempo di elaborazione. Inoltre, prova a impostare obiettivi di performance globali e locali e, una volta raggiunti, interrompi l'ottimizzazione :) –

+3

Se vuoi vedere un elenco delle operazioni extra che si verificano quando 'my' viene dichiarato all'interno del ciclo, puoi eseguire ognuna di esse gli script come questo e confrontano i diversi output: 'perl -MO = Conciso, -exec script.pl'. – FMc

risposta

10

La dichiarazione my in Perl ha due effetti principali; uno in fase di compilazione (in cui alloca uno slot sul blocco da appunti del sub contenente, e si assicura che tutti i riferimenti a tale nome all'interno dell'ambito appropriato siano risolti in quello specifico slot per i scratchpad) e uno di runtime (in cui esso reimposta il valore di quello slot pad a undef, o ad un valore particolare se hai scritto my $var = foo).

La porzione in fase di compilazione ha zero costi di runtime ammortizzati, ma la porzione di runtime viene eseguita ogni volta che l'esecuzione passa la mia dichiarazione. Come altri hanno sottolineato, i tuoi due esempi hanno prestazioni diverse perché hanno semantica diversa in generale - si cancella la variabile ogni volta attraverso il ciclo e l'altra no.

2

Il primo ciclo tenta di rendere la dichiarazione della variabile per ogni iterazione del ciclo e può comportare un tempo di elaborazione non necessario.

Concesso, non è molto, ma questa roba può aumentare nel tempo, ed è tecnicamente più lento poiché più istruzioni vengono eseguite per iterazione.

+2

Il compromesso è che si ottiene più isolamento (se si necessario) dal dichiararlo all'interno del ciclo. E va di pari passo con il principio che le variabili dovrebbero essere dichiarate sul più piccolo ambito che abbia senso. Naturalmente, se chiamerai qualcosa da 10 milioni di volte, non è necessaria la devozione servile allo standard. – Axeman

+0

Immagino di essere confuso perché pensavo che l'interprete assegnasse la memoria per ogni variabile prima dell'esecuzione? – flies

+0

credo che quello che sto chiedendo sia, che lavoro fa il compilatore per "rendere la dichiarazione della variabile" – flies

1

Bene, c'è il problema che stai dichiarando una nuova variabile con ogni iterazione.

Due, c'è il problema più grande dell'ambito dell'ambito.

Prova ad aggiungere questa riga dopo la for in ciascuno di quelli, e vedere cosa succede:

print $jimmy; 

E, provare anche questo:

my $jimmy; 
for (1..10000000) { 
    my $jimmy = $_**2; 
} 
print $jimmy; 

Un po 'più in dettaglio:

Un mio dichiara le variabili elencate a essere locali (in modo lessicale) alallegandoblocco, file o eval. Se è elencato più di un valore , l'elenco deve essere posto tra parentesi.

http://perldoc.perl.org/functions/my.html

Probabilmente troverete questo per essere un utile leggere così:

http://perldoc.perl.org/perlsub.html#Private-Variables-via-my%28%29

3

Dato che i programmi di esempio che hai dato non fanno veramente nulla, è difficile darti una ragione specifica per cui un tipo di dichiarazione sarebbe meglio dell'altro. Come molti altri poster hanno sottolineato, dichiarando che la variabile nel ciclo crea una nuova variabile ogni volta. Nei tuoi esempi la creazione è ridondante, ma considera i seguenti esempi usando le chiusure.

my @closures; 
my $jimmy; 

for (1 .. 10) { 
    $jimmy = $_** 2; 
    push @closures, sub {print "$jimmy\n"}; 
} 

e questo:

my @closures; 

for (1 .. 10) { 
    my $jimmy = $_** 2; 
    push @closures, sub {print "$jimmy\n"}; 
} 

In ogni caso il codice si accumula una serie di riferimenti al codice, ma nel primo esempio in quanto tutti i codici arbitri si riferiscono alla stessa $jimmy ognuno stamperà 100 quando chiamato. Nel secondo esempio ogni codice ref stamperà un numero diverso (1, 4, 9, 16, 25, ...)

Quindi in questo caso la differenza di orario non ha molta importanza dato che i due blocchi di codice fanno molto cose differenti.

0
  1. Dichiarare my fuori dal ciclo causa la dichiarazione che si verifica una volta. Durante la dichiarazione, perl riserva la memoria per quella variabile.

  2. Dichiarare my all'interno del ciclo causa la dichiarazione che si verifica a ogni intervallo del ciclo.

my è la risposta di Perl per dichiarare una variabile a livello locale - local è stato utilizzato per qualcos'altro e non significa la stessa cosa di cosa significherebbe in C. Quando si dichiara la variabile all'interno del ciclo, si è dichiarata in ambito locale al blocco del ciclo, in cui il blocco inizia/termina a ogni intervallo. Non solo è dichiarata la variabile, ma può anche essere ripulita (dereferenziata e/o impostata su undef) alla fine del blocco (anche se questo cambia dalle versioni Perl).

Le variabili dichiarate al di fuori del blocco del ciclo sono considerate "globali" (non letteralmente, ma nel senso del blocco del ciclo). Queste variabili riutilizzano le loro posizioni di memoria, piuttosto che dover cercare nuovi indirizzi.