Perl è un linguaggio con tipizzazione dinamica e alta flessibilità, che spesso porta a costi di prestazione impliciti se non utilizzato correttamente. L'ottimizzazione delle prestazioni è una parte fondamentale della manutenzione di script di medie e grandi dimensioni.
Sin dall'inizio, Perl è stato orientato alla velocità di prototipazione e all'integrazione rapida delle librerie. La vera ottimizzazione è arrivata dopo anni, con l'introduzione dei moduli di profilazione (Devel::DProf, NYTProf), dell'analisi delle allocazioni e dell'emergere delle buone pratiche consolidate.
I principali colli di bottiglia si verificano a causa della crescita incontrollata delle strutture, delle allocazioni non necessarie, della copia frequente dei dati e delle peculiarità poco chiare del funzionamento dell'interprete Perl, come ad esempio l'uso errato delle variabili globali e delle espressioni regolari inefficienti.
perl -d:NYTProf script.pl, dopo di che i rapporti vengono analizzati tramite nytprofhtmlundefEsempio di codice: — confrontare l'inline map con un ciclo semplice:
my @data = (1..1_000_000); my @result = map { $_ * 2 } @data; # potenzialmente più lento con calcoli complessi # vs my @result; foreach (@data) { push @result, $_ * 2; }
È sempre più veloce usare map rispetto a foreach?
No. Per le manipolazioni più semplici su piccoli array, non c'è quasi differenza, tuttavia espressioni complesse o il lavoro con grandi array possono rallentare a causa delle liste temporanee di map. In foreach si può controllare manualmente la memoria.
L'autovivificazione influisce sulle prestazioni?
Sì, soprattutto quando si creano casualmente grandi strutture annidate. La creazione automatica di nuovi livelli può consumare molta memoria molto rapidamente se si tenta di accedere casualmente a un hash non inizializzato in profondità nella struttura.
È obbligatorio dichiarare le variabili in anticipo tramite my per velocizzare?
Sì, ma non sempre per velocizzare: le variabili scoped-locale tendono a ottenere un accesso più veloce in Perl rispetto a quelle globali, tuttavia il guadagno reale dipende dalla dimensione del programma e dal numero di accessi.
Esempio:
my $sum = 0; foreach my $x (@big_array) { $sum += $x; }
In un grande script ETL, i log vengono elaborati map su milioni di record con espressioni regolari annidate. Lo script consuma memoria operativa e va in swap dopo 20 minuti di esecuzione.
Vantaggi:
Svantaggi:
È stata eseguita la profilazione, sono stati aggiunti cicli espliciti, le regex sono state suddivise in fasi, tutti i grandi array sono stati riconvertiti in riferimenti. Il tempo di esecuzione dello script è stato ridotto della metà, il consumo di memoria — di 10 volte.
Vantaggi:
Svantaggi: