La micro-ottimizzazione è importante durante la codifica?


178

Di recente ho posto una domanda su Stack Overflow per scoprire perché isset () era più veloce di strlen () in PHP . Ciò ha sollevato dubbi sull'importanza del codice leggibile e se vale la pena considerare anche i miglioramenti delle prestazioni dei micro-secondi nel codice.

Mio padre è un programmatore in pensione e gli ho mostrato le risposte. Era assolutamente certo che se un programmatore non prendesse in considerazione le prestazioni nel proprio codice anche a livello micro, non sarebbe un buon programmatore.

Non ne sono così sicuro - forse l'aumento della potenza di calcolo significa che non dobbiamo più considerare questo tipo di miglioramenti delle micro-prestazioni? Forse questo tipo di considerazione dipende dalle persone che scrivono il codice della lingua attuale? (di PHP nel caso precedente).

I fattori ambientali potrebbero essere importanti: Internet consuma il 10% dell'energia mondiale. Mi chiedo quanto siano micidiali pochi secondi di codice quando vengono replicati trilioni di volte su milioni di siti Web?

Mi piacerebbe conoscere le risposte preferibilmente basate su fatti riguardanti la programmazione.

La micro-ottimizzazione è importante durante la codifica?

Il mio riepilogo personale di 25 risposte, grazie a tutti.

A volte dobbiamo preoccuparci davvero delle microottimizzazioni, ma solo in circostanze molto rare. Affidabilità e leggibilità sono molto più importanti nella maggior parte dei casi. Tuttavia, considerare la microottimizzazione di volta in volta non fa male. Una comprensione di base può aiutarci a non fare ovvie scelte sbagliate durante la programmazione come

if (expensiveFunction() || counter < X)

Dovrebbe essere

if (counter < X || expensiveFunction())

( Esempio da @ zidarsk8 ) Questa potrebbe essere una funzione economica e quindi cambiare il codice sarebbe una micro-ottimizzazione. Ma, con una comprensione di base, non dovresti farlo, perché lo scriveresti correttamente in primo luogo.


123
Il consiglio di tuo padre è obsoleto . Non vorrei chiedere quanto migliora le prestazioni. Vorrei chiedere dove si trova il collo di bottiglia. Non importa se si migliora la prestazione di una sezione di codice se non fa alcuna differenza complessiva, il collegamento più lento determinerà la velocità. In PHP questo sta scrivendo sulla rete (a meno che tu non possa provare diversamente la misura di IE); che si traduce nella scrittura di un codice più leggibile è più importante.
Martin York,

61
Se si considera la parola chiave, non ha torto. Devi avere qualche indizio a riguardo.
JeffO

37
Sono triste perché la famosa citazione sull'ottimizzazione precoce non è stata ancora menzionata: "I programmatori sprecano enormi quantità di tempo pensando o preoccupandosi della velocità delle parti non critiche dei loro programmi e questi tentativi di efficienza hanno effettivamente un forte negativo impatto quando si considerano il debug e la manutenzione. Dovremmo dimenticare piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali . Eppure non dovremmo rinunciare alle nostre opportunità in quel 3% critico. "
Tamara Wijsman,

13
Puoi fornire una fonte sul "10% dell'energia mondiale"?
Michael Easter

17
coder does not consider performance in their code even at the micro level, they are not good programmersè molto diverso dalla microottimizzazione. È solo una buona codifica.
Woliveirajr,

Risposte:


90

Sono entrambi d'accordo e in disaccordo con tuo padre. Le prestazioni dovrebbero essere pensate in anticipo, ma la micro-ottimizzazione dovrebbe essere considerata in anticipo solo se si sa effettivamente che un alto percento del tempo sarà speso in piccole sezioni di codice associate alla CPU.

Il problema con la micro-ottimizzazione è che di solito viene fatto senza avere un'idea di come i programmi trascorrono effettivamente più tempo del necessario.

Questa conoscenza deriva dall'esperienza nel tuning delle prestazioni, come in questo esempio , in cui un programma apparentemente semplice, senza evidenti inefficienze, viene seguito attraverso una serie di passaggi di diagnosi e accelerazione, fino a quando è 43 volte più veloce rispetto all'inizio.

Ciò che mostra è che non puoi davvero indovinare o intuire dove saranno i problemi. Se si esegue la diagnosi, che nel mio caso è una pausa casuale , le righe di codice responsabili di una frazione significativa di tempo vengono esposte preferenzialmente. Se li guardi, potresti trovare un codice sostitutivo, e quindi ridurre il tempo complessivo di circa quella frazione.

Altre cose che non hai risolto richiedono ancora più tempo di prima, ma poiché il tempo complessivo è stato ridotto, quelle cose ora richiedono una frazione maggiore, quindi se lo fai di nuovo, anche quella frazione può essere eliminata. Se continui a farlo su più iterazioni, è così che puoi ottenere enormi accelerazioni, senza aver necessariamente necessariamente fatto alcuna micro-ottimizzazione .

Dopo questo tipo di esperienza, quando si affrontano nuovi problemi di programmazione, si arriva a riconoscere gli approcci progettuali che inizialmente portano a tali inefficienze. Nella mia esperienza, deriva dalla sovra-progettazione della struttura dei dati, dalla struttura dei dati non normalizzata, dall'enorme dipendenza dalle notifiche, da quel genere di cose.


120

La micro-ottimizzazione è importante solo se i numeri dicono che lo è.

I requisiti che si stanno sviluppando dovrebbero avere alcune specifiche dei dati sulle prestazioni, se le prestazioni rappresentano un problema per il cliente o l'utente. Durante lo sviluppo di software, è necessario testare le prestazioni del sistema in base a questi requisiti. Se non si soddisfano i requisiti di prestazione, è necessario profilare la base di codice e ottimizzare in base alle esigenze per raggiungere i requisiti di prestazione. Una volta raggiunte le prestazioni minime richieste, non è necessario estrapolare altre prestazioni dal sistema, soprattutto se si intende compromettere ulteriormente la leggibilità e la manutenibilità del codice (nella mia esperienza, il codice altamente ottimizzato è meno leggibile e mantenibile, ma non sempre). Se puoi ottenere ulteriori miglioramenti delle prestazioni senza degradare gli altri attributi di qualità del sistema,

Ci sono casi, tuttavia, in cui le prestazioni sono della massima importanza. Penso principalmente ai sistemi in tempo reale e ai sistemi integrati. Nei sistemi in tempo reale, cambiare l'ordine delle operazioni può avere un effetto enorme sul rispetto delle scadenze rigide necessarie per un corretto funzionamento, forse anche influenzando i risultati dei calcoli. Nei sistemi embedded, in genere hai memoria, potenza della CPU e potenza limitate (come in batteria), quindi è necessario ridurre le dimensioni dei file binari e ridurre il numero di calcoli per massimizzare la durata del sistema.


D'altra parte, se c'è un problema tra l'uso di una funzione più lenta o più veloce, non c'è motivo di usare la funzione più lenta - come qui in caso di isset.
Mavrik,

7
@Mavrik È vero. Se hai due funzioni, X e Y, e Y è più veloce di X (almeno per le tue condizioni particolari), non c'è motivo di non usare Y, se il codice è ancora leggibile e gestibile. Ma se non conosci Y e devi refactificare il codice per usare Y invece di X e le prestazioni (di quel segmento di codice) non sono un problema, non c'è motivo di apportare tale modifica. Si tratta di compromessi: prestazioni, tempi, costi, sforzi, leggibilità / manutenibilità e così via.
Thomas Owens

2
Concordo con tutto il cuore, volevo solo fare questo punto quando si tratta di micro-ottimizzazione - se non ti costa nulla in termini di leggibilità / tempo, fallo. Altrimenti no.
Mavrik,

Il codice +1 altamente ottimizzato è meno leggibile e gestibile ... ma non sempre.
Boz,

Altri casi in cui le prestazioni sono importanti: (1) gioco; (2) grandi quantità di dati; (3) sito web ad alto traffico; (4) reattività di un'interfaccia utente altamente complessa; (5) servizio che dovrebbe essere eseguito in background come il controllo dei virus; (6) finanziamento; (7) smartphone; e così via. È appena limitato a casi esoterici come RTS e sistemi integrati.
Rex Kerr,

103

Ogni volta che qualcuno chiede informazioni sull'ottimizzazione , mi viene in mente la citazione di Michael A. Jackson

La prima regola di ottimizzazione del programma: non farlo.

La seconda regola di ottimizzazione del programma (solo per esperti!): Non farlo ancora .

Citazione da Wikipedia corretta per l'inglese britannico. * 8' )

Nella seconda regola è implicito profilare il tuo codice e passare solo il tempo a ottimizzare le cose che faranno la differenza.

Durante la programmazione in assemblea, l'affermazione di tuo padre era corretta. Ma questo è molto più vicino al metal di quanto la maggior parte delle persone programmi al giorno d'oggi. Oggi anche provare a ottimizzare te stesso (senza profilazione) può portare a rendere il tuo codice più lento rispetto a se avessi fatto qualcosa nel modo più comune, poiché è più probabile che il modo comune venga ottimizzato dai moderni compilatori JIT .

Anche in C devi essere abbastanza bravo nell'ottimizzazione per sapere di più su come ottimizzare una sezione di codice rispetto al compilatore.

Se non hai familiarità con gran parte di ciò di cui parla Ulrich Drepper nel suo eccellente documento Cosa ogni programmatore dovrebbe sapere sulla memoria , allora probabilmente stai perdendo anche il tentativo di ottimizzarti. Contrariamente al titolo dei giornali, tuttavia (che in realtà è un omaggio al altrettanto fantastico di What Gold Scientist Dovrebbe sapere sull'aritmetica a virgola mobile ) non avere questo livello di comprensione non necessariamente ti impedisce di essere un buon programmatore, solo un diverso tipo di programmatore.

isset()vs. strlen()in PHP

Non conosco PHP, quindi non è davvero ovvio cosa isset()debba fare. Posso dedurlo dal contesto, ma ciò significa che sarà altrettanto oscuro per i programmatori PHP alle prime armi e potrebbe anche causare doppi programmatori più esperti. Questo è il tipo di uso idiomatico di un linguaggio che può rendere la manutenzione un incubo.

Non solo, ma non vi è alcuna garanzia che isset()sarà sempre più efficiente, solo perché ora è più efficiente. Un'ottimizzazione ora potrebbe non essere un'ottimizzazione il prossimo anno o tra 10 anni. CPU, sistemi, compilatori migliorano e cambiano nel tempo. Se le prestazioni di PHP strlen()sono un problema, PHP potrebbe essere modificato in futuro, quindi potrebbe essere necessario rimuovere tutte le ottimizzazioni isset () per ottimizzare nuovamente il codice.

Ogni ottimizzazione ha il potenziale per diventare una futura anti-ottimizzazione , quindi dovrebbe essere considerata un possibile odore di codice, da ridurre al minimo.

Un esempio per esperienza personale

Come esempio di tale anti-ottimizzazione , una volta ho dovuto disinfettare una base di codice enorme piena di codice del modulo if x==0 z=0 else z=x*yperché qualcuno aveva ipotizzato che una moltiplicazione in virgola mobile sarebbe sempre stata più costosa di un ramo. Sull'architettura di destinazione originale questa ottimizzazione ha reso il codice più veloce, ma i tempi cambiano.

Quando abbiamo provato a utilizzare questo codice su una CPU più moderna che era altamente pipeline, le prestazioni erano orribilmente pessime - ognuna di queste affermazioni causa un flush della pipeline. Semplificare tutte queste righe di codice per z=x*yrendere il programma più veloce nell'ordine di grandezza della nuova architettura, ripristinando le prestazioni perse dall'anti-ottimizzazione .

I problemi che di solito dobbiamo ottimizzare per oggi sono molto diversi da quelli che abbiamo dovuto ottimizzare per 20 o anche 10 anni fa.

Quindi ci siamo preoccupati di fare la maggior parte del lavoro per ogni ciclo di clock, ora è più probabile che ci preoccupiamo di svuotamenti della pipeline, previsioni errate sui rami e mancate cache a livello di CPU, ma i blocchi e la comunicazione tra processi stanno diventando molto più significativi mentre passiamo al multi- architetture di processo e multiprocessore. Il documento di Drepper può davvero aiutare a comprendere molti di questi problemi.


3
Pipeline flush e cache miss è ciò che vuoi evitare: D Hanno costi orribili. ma solo su parti di codice che li eccitano molte molte molte molte molte volte.
deadalnix,

7
Una cosa che aggiungerei è che i compilatori hanno fatto molta strada e ottimizzeranno molte cose per te. AFAIK, fanno meglio a ottimizzare codice pulito e leggibile rispetto alle cose difficili.
Becuzz

3
+1 per aver fornito un vero esempio di micro-ottimizzazione che ha perso tempo e ha rivelato che Michael Jackson era un programmatore.
Boz,

1
+1 Per l'esempio. Illustra perfettamente perché dovresti lasciare banali trasformazioni al compilatore.
back2dos

1
@Rex Kerr> nell'esempio, il costo deriva dalla ramificazione, che causa lo svuotamento della pipeline della CPU. Anche la moltiplicazione in virgola mobile è costosa. Ciò che è più costoso dipende fortemente dalla FPU e dalla lunghezza della pipeline della CPU che esegue il codice. Non sarei sorpreso che questo codice funzionasse più velocemente su CPU più vecchie con pipeline più brevi e FPU meno efficienti rispetto alla CPU corrente.
deadalnix,

84
  1. Scrivi un codice che sia pulito, conciso, semplice e autoesplicativo.
  2. Effettuare test delle prestazioni per identificare i colli di bottiglia.
  3. Ottimizza le sezioni critiche.

Come regola generale: il 95% del codice viene eseguito il 5% delle volte. Non ha senso ottimizzare prima di creare un profilo / benchmark del codice e vedere quali sono il 5% che viene eseguito il 95% delle volte.

Ogni idiota può fare la micro-ottimizzazione e qualsiasi compilatore / runtime decente lo farà per te.
L'ottimizzazione del buon codice è banale. Scrivere codice ottimizzato e cercare di renderlo buono dopo ciò è noioso nella migliore delle ipotesi e insostenibile nella peggiore.

Se ti preoccupi seriamente delle prestazioni, non utilizzare PHP per codice critico per le prestazioni. Trova i colli di bottiglia e riscrivili con le estensioni C. Anche la micro-ottimizzazione del codice PHP oltre il punto di offuscamento non ti darà la stessa velocità.

Personalmente, mi è piaciuta molto la micro-ottimizzazione quando ho iniziato a programmare. Perché è ovvio. Perché ti premia rapidamente. Perché non devi prendere decisioni importanti. È il mezzo perfetto di procrastinazione. Ti consente di scappare dalle parti davvero importanti dello sviluppo del software: la progettazione di sistemi scalabili, flessibili, estensibili e robusti.


2
La migliore risposta per me è stata trovata, straordinariamente, nella Guida per gli sviluppatori di Bugzilla: "Se stai cercando di essere intelligente invece di cercare di essere leggibile, allora forse stai cercando di rendere le cose" più veloci? "In tal caso, ricorda : non risolvere un problema prima di sapere che esiste. Se non sai (con test dettagliati e reali) che il tuo codice è lento, non preoccuparti di renderlo "più veloce". ottimizzazione: molti programmatori risolvono costantemente problemi che nessuno ha mai avuto. Non farlo. " bugzilla.org/docs/developer.html#general
Marco

7
In genere sono d'accordo - fatta eccezione per una riga, sostengo che "ogni idiota pensa di poter microottimizzare" ...;)
Nim

@Nim: punto preso;)
back2dos

26

Concordo con tuo padre: "Se un programmatore non considera le prestazioni nel proprio codice anche a livello micro, non sono dei buoni programmatori". La chiave è "considerare le prestazioni". Ciò non equivale a "fare micro-ottimizzazioni ad ogni passo".

Sono d'accordo con la maggior parte degli altri commenti - ciò che un tempo rendeva i programmi C più veloci potrebbe non farlo oggi - ma ci sono altre cose serie da considerare: dovrei usare C o C ++? Le classi con semplici operatori sovraccarichi possono compromettere le prestazioni se le usi molto. È importante? Dipende dalla tua applicazione, ma se non la CONSIDERA nemmeno, non sei un programmatore molto bravo. Alcune persone potrebbero considerarlo per circa 2 millisecondi e respingerlo, ma penso che troppi letteralmente non lo considerino nemmeno.

La realtà è che con l'ottimizzazione, il codice può diventare più difficile da leggere. La scrittura del codice richiederà più tempo. Il codice sarà tra un po 'più veloce e un ordine di grandezza più veloce (è raro). I tuoi clienti probabilmente non conosceranno la differenza.

Un'altra realtà è che alla gente piace riutilizzare il codice, e dove finisce potrebbe essere molto diverso rispetto a quando l'hai scritto. All'improvviso alla gente potrebbe interessare.

Ad esempio, supponi di aver scritto qualcosa come Angry Birds su un PC o per una console di gioco. Hai ignorato l'ottimizzazione nel tuo sistema fisico e nel tuo sistema grafico, perché oggigiorno i dual core a 2,5 GHz sono sostanzialmente il minimo e il tuo gioco funziona abbastanza bene. Quindi arrivano gli smartphone e si desidera portarlo. Oh maledizione, un core ARM a 600 MHz ?

Pensa a un sito web - qualcosa messo insieme in un fine settimana come Hot or Not . Usi qualunque database sia utile, scrivi tutto pensando a un rapido sviluppo, lanciando un URL via e-mail ai tuoi amici. Tre mesi dopo il tuo server sta morendo per sovraccarico e non puoi fare nulla per ridimensionare. Succede tutto il tempo. I siti Web più grandi hanno bollette della potenza misurate in centinaia di kilowatt o addirittura megawatt. Pensaci, ci sono megawatt da salvare attraverso l'ottimizzazione del codice.

Come ha detto tuo padre, devi almeno considerarlo . La maggior parte delle persone non sa nemmeno quanta performance ci sia sul tavolo e ci passa sopra con una rapida battuta su "ottimizzazione prematura" e "non farlo". Questi non sono buoni programmatori.

Questa non è un'opinione popolare su questi siti. Ciao ciao punti reputazione ....


3
Certo, dovresti prenderlo in considerazione (nella parte posteriore della testa) e in genere respingerlo, a meno che non ne valga la pena. È necessario considerare che le ottimizzazioni di solito riducono la leggibilità del codice e possono aumentare il tempo impiegato per il codice e mantenerlo di un fattore di circa 10. Se il programma non richiede molta CPU, spesso non è necessario. Riconosci che il tuo compilatore è in genere molto più bravo nell'ottimizzare di te, e che molte delle tue ottimizzazioni danneggiano effettivamente le prestazioni. Se non vale la pena dedicare il tuo tempo a testare ottimizzazioni e profilo, non vale la pena dedicare il tuo tempo all'ottimizzazione.
dr jimbob,

3
Il vostro esempio Angry Birds mostra esattamente il motivo per cui si dovrebbe non ottimizzare prematuramente. Nel porting da desktop a console su dispositivi mobili, hai a che fare con (almeno) tre tipi molto diversi di hardware e l'ottimizzazione per uno potrebbe danneggiare invece di aiutare su un altro. Peggio ancora, l'ottimizzazione renderà il codice più difficile da capire, quindi più difficile da portare. Certo, scegli algoritmi efficienti fin dall'inizio, ma salva la micro-ottimizzazione per la fase di ottimizzazione delle prestazioni quando i dati reali ti diranno dove si trova il problema su ciascuna piattaforma.
Caleb,

@Caleb: L'esempio di Angry Birds illustra perché non ottimizzare un determinato hardware. Illustra inoltre come è possibile creare un'intera app senza preoccuparsi di eseguire ottimizzazioni di "livello C" più generali e quindi di bruciarsi. In realtà non bruciato, ma avendo problemi ad andare oltre il tuo intento originale.
Phkahler,

25

Per prima cosa prendiamo il tuo caso: PHP

  • Non credo che PHP sia un tipo di linguaggio (sia per la sua natura che per il suo principale dominio di applicazione) che devi preoccuparti di queste "micro-ottimizzazioni". Il codice PHP è principalmente ottimizzato con la cache del codice operativo.
  • I programmi scritti in PHP non sono associati alla CPU, sono principalmente legati all'I / O , quindi queste ottimizzazioni non varranno comunque il tuo tempo.
  • Tutto ciò che DEVI ottimizzare dovrebbe probabilmente essere inserito in un'estensione C e quindi caricato dinamicamente nel runtime di PHP
  • Come puoi vedere, non otteniamo alcun incentivo micro-ottimizzando il nostro codice in PHP - d'altra parte, se passi quel tempo a rendere il codice PHP più leggibile e gestibile - ciò ti pagherà più dividendi.

In generale,

Non passerei molto tempo "TOOOOO" a ottimizzare il mio codice in un linguaggio dinamico come Python o Ruby , perché NON sono progettati per attività che richiedono un numero elevato di CPU. Risolvono diverse classi di problemi in cui modellare una situazione del mondo reale in modo elaborato (che è facile da leggere e mantenere) - che si chiama espressività - è più importante della velocità. Se la velocità fosse la preoccupazione principale, non sarebbero dinamici in primo luogo.

Per i programmi compilati (C ++, Java), l'ottimizzazione è più cruciale. Ma anche lì, prima devi guardare la natura / dominio / scopo del programma che stai scrivendo. Dovresti anche valutare attentamente il tempo di micro-ottimizzazione rispetto ai guadagni derivanti da tale ottimizzazione. Se hai bisogno di ancora più ottimizzazione, allora puoi anche considerare di fare un passo verso il basso e codificare quei pezzi del tuo codice in assembler.

Quindi, per rispondere alla tua domanda originale: "La micro-ottimizzazione è importante durante la codifica?" -- la risposta è, dipende --

  • Che tipo di cosa stai facendo: dominio dell'applicazione, complessità?
  • I miglioramenti della velocità dei microsecondi sono DAVVERO importanti per il tuo programma?
  • Quale tipo di ottimizzazione sarà più redditizia? Potrebbe non essere sempre l'ottimizzazione del codice, ma qualcosa di esterno.
  • Quanta "bontà" (in termini di velocità) stai raccogliendo dal tempo che investi nella micro ottimizzazione?
  • È possibile ottenere velocità migliori in altri modi: modificando hardware, RAM e processore, eseguendo il codice in parallelo o su un sistema distribuito?

Non solo la micro-ottimizzazione (ottimizzazione del codice per quella materia) richiede tempo, ma "distorce" la leggibilità naturale del tuo codice, rendendolo così pesante per la manutenzione. Consideralo sempre l'ultima risorsa: cerca sempre di ottimizzare l'intera applicazione adottando hardware e architettura migliori rispetto all'ottimizzazione dei singoli file di codice.


18

Sembra che ci siano molte risposte che affermano che la micro ottimizzazione è

tutto sui compromessi: prestazioni, tempi, costi, sforzi, leggibilità / manutenibilità e così via.

Ma bene so che ci sono alcune ottimizzazioni in cui non vi è alcun impatto sulla leggibilità, e mi piace solo fare quelle per divertimento. Ho visto in alcuni dei miei compiti scolastici (che erano tutti basati sulla velocità), che è sempre bello considerare la micro ottimizzazione quando si scrivono dichiarazioni condizionali come:

if (counter < X && shouldDoThis()) // shouldDoThis() is an expensive function

è sempre più bello di

if (shouldDoThis() && counter < X ) 

Esistono diversi modi per "accelerare" il tuo codice in questo modo e la differenza è generalmente trascurabile (non sempre però), ma mi sento meglio se lo scrivo in quel modo.

Non so se qualcuno lo consideri addirittura come un'ottimizzazione, ma penso che un programmatore dovrebbe sapere e considerare queste cose quando scrive il proprio codice.


2
Potrebbe non essere importante per questo caso particolare . Tuttavia penso che sia molto importante essere in grado di riconoscere le ottimizzazioni come questi in modo che quando si fa materia, non c'è bisogno di spendere inutilmente tempo profiling e l'ottimizzazione dopo il fatto.
tskuzzy,

4
Questo è un esempio molto pericoloso . Un'ottimizzazione dovrebbe mai cambiare il comportamento . Anche suggerire che si cheap() && expensive()tratta di un'ottimizzazione di expensive () && cheap()invita le persone a sostituire ciecamente l'una con l'altra senza tener conto del significativo cambiamento semantico che crea (nelle lingue in cui si &&trova l'operatore di cortocircuito).
Mark Booth,

5
Se le funzioni non hanno effetti collaterali, sono equivalenti e una è più veloce. Se hanno effetti collaterali, non si dovrebbe in primo luogo scrivere il codice in questo modo. Direi persino che questo dovrebbe essere fatto per abitudine, a meno che non cambi effettivamente comportamento.
Phkahler,

3
@MarkBooth Qui sono d'accordo con Phkahler, nessuna di queste funzioni dovrebbe avere effetti collaterali! L'ordine dei condioni in un'istruzione if non deve influire sull'esito del programma. Il mio esempio sarebbe meglio scritto come if (x<100 && isPrime(x)), solo per renderlo più chiaro.
zidarsk8,

1
@ zidarsk8 - Se un'ottimizzazione cambia qualcosa di diverso dalla velocità di esecuzione, non è un'ottimizzazione . Come programmatori spesso dobbiamo essere pragmatici , e talvolta ciò significa che non possiamo garantire che tutte le funzioni utilizzate con un operatore di cortocircuito siano pure, specialmente quando il nostro codice chiama librerie di terze parti sulle quali non abbiamo alcun controllo. In quella situazione devi stare attento che i programmatori inesperti non sono incoraggiati a introdurre bug in nome dell'ottimizzazione .
Mark Booth,

11

All'inizio della mia carriera, affermazioni generali come "non micro-ottimizzare" hanno creato molta confusione. Tutto è circostanziale; quindi, il motivo per cui la gente dice "best practice" piuttosto che "farlo".

"Best practice" è la scelta migliore considerando tutte le circostanze. Ad esempio, LINQ ed Entity Framework dovrebbero essere usati al posto di SQL inline. Nella mia azienda siamo su SQL Server 2000 . SQL Server 2000 non supporta Entity Framework. Le migliori pratiche richiedono:

  • Vendo il mio capo sull'idea di acquistare una nuova versione di SQL Server che significa diverse migliaia di dollari.
  • Vendere sviluppatori sull'idea di apprendere nuove tecnologie.

So per esperienza che questo non accadrà. Quindi, ho potuto smettere, sottolineare fino in fondo o non seguire le migliori pratiche.

Ci sono considerazioni politiche, tecniche e monetarie alla base delle decisioni che incidono sul risultato complessivo. Ricorda questo fatto quando prendi una decisione e scegli saggiamente le tue battaglie.

" Per ogni cosa c'è una stagione, un tempo per ogni attività sotto il cielo. "


1
A proposito, puoi usare Dapper come alternativa micro-ORM per incorporare SQL.
Dan

2
LINQ and Entity Framework should be used in lieu of inline SQL- Fino a quando non hai effettivamente bisogno di SQL inline per ottimizzare qualcosa; l'SQL che EF produce non è sempre ottimale.
Robert Harvey,

1
in seguito, se il tuo capo è preoccupato per i costi di licenza di SQL 2k8 (o qualsiasi altra cosa possa essere attuale), dovresti sottolineare che è abbastanza vecchio per essere pubblicato su EOL MOLTO presto (se non lo è già)
Warren

@warren - Alcune aziende non prendono in considerazione queste cose. Per alcuni, se "funziona" ancora, non si aggiorneranno. Per lavoro, intendo dire che il server funziona ancora. Vediamo già una mancanza di supporto con EF. Questo semplicemente non è abbastanza per convincerli a spendere soldi.
P.Brian.Mackey,

1
Proprio per questo sai, puoi usare EF con SQL 2000. Il progettista non funziona, ma l'attuale framework di entità supporta SQL 2000. Per aggirare la limitazione del progettista, puoi creare un database locale in sql 2008 express con lo stesso schema come database sql 2000, punta il progettista su quello per generare tutte le classi, quindi vai nel file .edmx e modifica la versione del database di destinazione in 2000 e punta la stringa di connessione sul tuo database sql server 2000. Non è la soluzione migliore, ma se non riesci ad aggiornare funziona.
Neil,

8

Questo è sempre un compromesso.

In primo luogo, l'industria dei computer riguarda i soldi alla fine. Quello che devi fare come sviluppatore è generare valore per il cliente in modo da ottenere denaro (questa è una semplificazione eccessiva ma il punto principale è qui).

Il tempo degli sviluppatori costa denaro. Anche la potenza della macchina costa denaro. Di solito, questo secondo costo è molto più basso del primo. Quindi, questo è capitale per avere un codice leggibile e un codice gestibile, in modo che lo sviluppatore possa dedicare la maggior parte del proprio tempo a fornire valore.

La micro-ottimizzazione può, in alcuni casi, essere importante. Ma di solito implicano un codice meno leggibile o un codice meno estensibile (questo non è il caso del tuo esempio collegato, ma in generale lo è). Questo costerà a un certo punto il tempo dello sviluppatore. Questa volta essendo più costoso della potenza della macchina, questo è uno spreco.

In secondo luogo, la micro-ottimizzazione in un progetto di grandi dimensioni può rendere sempre più difficile mantenere / evolvere. Il problema è che quando si evolve, qualche altra ottimizzazione potrebbe ora essere impossibile da fare. Con un'applicazione in evoluzione, in genere ti ritroverai con una soluzione più lenta di quella che avresti avuto senza fare quelle ottimizzazioni.

In terzo luogo, l'ottimizzazione è spesso irrilevante poiché la complessità dell'algoritmo in genere supererà qualsiasi micro-ottimizzazione che si sarebbe potuto fare se il set di dati cresce. Sfortunatamente, poiché la micro-ottimizzazione rende il tuo codice più difficile da mantenere / evolvere, questa ottimizzazione potrebbe essere più difficile da fare.

A volte, il valore sta in questa ottimizzazione (pensa ai programmi critici di latenza, come nei videogiochi o al pilota automatico di un aereo). Ma questo deve essere dimostrato. Di solito il tuo programma passa la maggior parte del tempo in una porzione limitata di codice. Qualunque sia la micro-ottimizzazione che fai, non otterrai mai i tuoi programmi più velocemente senza identificare il collo di bottiglia e lavorare su questa parte.

Fare la tua domanda come hai fatto ha dimostrato che non hai confrontato il problema con un programma reale. In questo caso, avresti potuto fare il trucco e notare se era più veloce o meno. Quindi lo stavi chiedendo prima di avere qualche problema. Questo è dove si trova il problema. Stavi gestendo il problema dell'ottimizzazione nel modo sbagliato.

Poiché la manutenzione e l'evoluzione sono generalmente più preziose della micro-ottimizzazione, assicurati di avere l'interfaccia giusta prima di procedere. Quindi se parti del tuo programma sono abbastanza astratte l'una per l'altra, puoi micro-ottimizzarne una senza rovinare tutto. Ciò richiede che l'interfaccia sia in esecuzione per il tempo necessario per essere attendibile.


"C'è sempre un compromesso". È vero, ridurre una variabile aumenterà l'altra, se il programma è sulla curva di compromesso . In base alla mia esperienza, la maggior parte dei programmi non si trova vicino alla curva di compromesso e ha molto spazio per ridurre entrambe le variabili.
Mike Dunlavey,

La manutenzione e l'evoluzione +1 sono più preziose della microottimizzazione. Anche se sono sicuro che l'industria dei computer non riguarda solo i soldi? Ad esempio, open source, istruzione, innovazione, governance, comunità, ecc. Sono sicuro che i soldi possono essere trovati alla radice di esso, ma questo è vero per la maggior parte delle cose.
Boz,

@Boz kay> Questo è parzialmente vero. Innanzitutto perché il tuo capo e il tuo cliente per lo più non sanno nulla di questi e si preoccupano dei soldi. Se vuoi promuovere alcuni strumenti open source, devi dire loro come migliorerà il marchio dell'azienda o come ridurrà i costi di sviluppo. Inoltre, rendere felici gli sviluppatori è un modo per ottenere buoni sviluppatori nella tua azienda. Un buon sviluppatore guadagna (principalmente lanciando qualità e innovazione). Alla fine, il denaro è la chiave. E sto scrivendo che dal mio computer Linux diventa un grande sostenitore del software libero. Lo stesso vale per l'educazione.
deadalnix,

8

Le prestazioni sono una caratteristica

L'articolo di Jeff Atwood è eccezionale sulla costruzione di un sito Web ad alte prestazioni e sull'importanza di farlo ...

Detto questo, non concentrarti sulla micro-ottimizzazione fino a quando non è necessario. Esistono ulteriori ottimizzazioni vantaggiose che è possibile eseguire. Concentrati sull'architettura, non sul codice. La maggior parte dei siti Web che ho visto che hanno funzionato lentamente ha avuto problemi di alto livello (livello di servizio Web non necessario, scarsa progettazione del database, architetture eccessivamente complicate) che non solo incidevano negativamente sulle prestazioni ma erano profondamente radicati e difficili da risolvere.

Quando si crea un sito Web, è molto più probabile che il codice lato client e la logica del database causino problemi di prestazioni rispetto al codice lato server. Come ogni altra cosa, se hai problemi di prestazioni, lo saprai, profila ancora meglio il tuo codice e puoi trovarlo presto.


7

Il tempo degli sviluppatori costa più del tempo del computer. Di solito è quello che vuoi ottimizzare. Ma:

  • C'è una differenza tra micro-ottimizzazione e complessità algoritmica. Trascorrere abbastanza tempo per essere sicuri di utilizzare l' algoritmo giusto .
  • Assicurati di porre la domanda giusta, select (select count(*) from foo) >= 1non è la stessa cosa di select exists(select 1 from foo).
  • alcuni idiomi linguistici sono popolari semplicemente perché sono più veloci, va bene usarli, poiché la maggior parte degli utenti fluenti della lingua li conosceranno. (il tuo esempio è un buon esempio).

7

Cosa vuoi ottimizzare?

  • Prestazioni del software?
  • Affidabilità?
  • Produttività del programmatore?
  • Soddisfazione del cliente?
  • Efficienza Energetica?
  • Manutenibilità?
  • Time to market?
  • Costo?

"Ottimizza" non significa sempre eseguire il codice il più velocemente possibile. Ci sono momenti in cui trovare il modo più veloce in assoluto per fare qualcosa è importante, ma non è poi così comune nella maggior parte del codice. Se gli utenti non riescono a notare la differenza tra 50 e 100 microsecondi, in realtà non c'è alcuna differenza tra i due codici che verranno eseguiti solo occasionalmente. Ecco un esempio:

Se è necessario aggiornare continuamente una visualizzazione della lunghezza dell'input dell'utente e della quantità di tempo impiegata da una delle due routine per determinare che la lunghezza è molto più piccola del tempo tra due sequenze di tasti consecutivi, non importa quale routine usate. D'altra parte, se è necessario determinare la lunghezza di un miliardo di stringhe, è consigliabile prestare molta attenzione alle differenze di prestazioni tra le diverse routine. Nel primo caso, potresti preferire scrivere codice che sia facile da capire e da verificare; nel secondo caso, potresti essere disposto a scambiare la leggibilità per la velocità.

In ogni caso, se hai intenzione di ottimizzare il tuo codice, dovresti profilare il tuo codice prima e dopo ogni modifica che apporti. I programmi in questi giorni sono abbastanza complicati che spesso è difficile dire dove si trovano i colli di bottiglia; la profilazione ti aiuta a ottimizzare il codice giusto e quindi a dimostrare che le ottimizzazioni fatte hanno funzionato davvero.

Non hai detto quando tuo padre si è ritirato o che tipo di programmazione ha fatto, ma la sua reazione non è sorprendente. Storicamente, la memoria, la memoria secondaria e i tempi di elaborazione erano tutti costosi e talvolta molto costosi. In questi giorni, tutte queste cose sono diventate molto economiche rispetto al tempo del programmatore. Allo stesso tempo, processori e compilatori sono diventati in grado di ottimizzare il codice in modi che i programmatori non avrebbero mai potuto eguagliare. I giorni in cui i programmatori usano piccoli trucchi per cancellare alcune istruzioni della macchina qua e là sono per lo più andati.


1
+1 Per non parlare del fatto che negli ultimi anni i dispositivi mobili sono tornati fortemente dipendenti dall'ottimizzazione del codice. Qualcuno che non scrive codice ottimizzato o almeno lo considera potrebbe avere difficoltà a far funzionare senza problemi la propria app ad alta intensità di CPU su un dispositivo mobile.
Styler

+1 molto simile al tuo elenco di possibili ottimizzazioni. Ha usato assembly / fortran
Boz il

@Styler: non passerà molto tempo prima che i dispositivi mobili dispongano di CPU quad core con GB di memoria, abbiamo già smartphone dual core.
Sdraiati Ryan il

@Lie Ryan: sì, è vero, ma come la maggior parte dei pionieri hanno dovuto viaggiare in barche di legno;)
Styler

7

Non è importante ottimizzare il micro durante la scrittura del codice. L'ottimizzazione dovrebbe essere fatta con l'aiuto di un profiler, ottimizzando il codice dove è importante.

TUTTAVIA , un programmatore dovrebbe cercare di evitare di fare cose ovviamente stupide mentre scrive il codice.

Ad esempio, non eseguire ripetute operazioni costose all'interno di un ciclo. Memorizza il valore in una variabile esterna al loop e usalo. Non fare cose come confronti di stringhe o regex più e più volte in una funzione spesso chiamata, quando puoi salire di livello, fare il confronto e trasformarlo in un numero intero o un riferimento di funzione o una classe derivata.

Queste cose sono facili da ricordare per un programmatore esperto e quasi sempre migliorano la qualità del codice.


Realizzato che ho bisogno di essere più chiaro nella modifica della domanda, stavo dicendo la stessa cosa, l'ho aggiornato.
Boz,

7

Quando decidi cosa ottimizzare, ricorda sempre la legge di Amdahl . Vedi il link per la matematica precisa; l'affermazione pithy da ricordare è:

Se una parte del programma rappresenta il 10% del suo tempo di esecuzione e la parte viene ottimizzata per l'esecuzione due volte più veloce, il programma nel suo insieme accelera solo del 5%.

Questo è il motivo per cui la gente dice sempre che non vale la pena ottimizzare parti del programma che non occupano più di qualche percento del tempo di esecuzione totale. Ma questo è solo un caso speciale di un principio più generale. La legge di Amdahl ti dice che se devi far funzionare l'intero programma due volte più velocemente, devi accelerare ogni pezzo in media del 50%. Ti dice che se devi elaborare venti gigabyte di dati, ci sono solo due modi per farlo andare più veloce del tempo necessario per leggere venti gigabyte dal disco: ottenere un disco più veloce o ridurre i dati.

Cosa dice la legge di Amdahl sulle microottimizzazioni? Dice che forse ne valgono la pena se si applicano su tutta la linea. Se riesci a radere dell'uno percento il tempo di esecuzione di ogni funzione nel tuo programma, congratulazioni! Hai accelerato il programma dell'uno percento. Valeva la pena farlo? Beh, come compilatore sarei felice di trovare un'ottimizzazione che lo ha fatto, ma se lo fai a mano, direi di cercare qualcosa di più grande.


1
+1 per la citazione di Amdahl, ma non sono d'accordo con "per far funzionare l'intero programma due volte più veloce, è necessario accelerare ogni pezzo". Direi che non acceleri davvero nessun "pezzo". Piuttosto, trovi lavoro inutile ed eliminalo. Soprattutto le chiamate di funzione, se il programma è qualcosa di più grande di un giocattolo. Gran parte del pensiero comune sulle prestazioni sembra ignorare completamente l'importanza di trovare interi rami non necessari dell'albero delle chiamate (che possono essere singole istruzioni) e di eliminarli.
Mike Dunlavey,

Il diavolo è nella parola "media" lì. È matematicamente il caso che per accelerare un programma del 50% ogni pezzo debba essere accelerato del 50% in media . Ora, se riesci a dividere il programma in un lavoro che richiede il 75% di tempo di esecuzione e un altro che richiede il 25% e velocizzare il primo a 3 volte, questo ti darà il 50% in generale, nonostante non abbia fatto nulla a quest'ultimo lavoro. Ma il caso molto più comune è che ci sono dozzine di "lavori" che richiedono ciascuno meno del 5% del tempo di esecuzione - e quindi è necessario accelerare o sbarazzarsi di molti di essi.
zwol,

Penso che ci sia un caso ancora più comune. C'è un "lavoro" che richiede il 50% delle volte, ma in realtà non ne hai bisogno , quindi lo rimuovi completamente, riducendo il tempo complessivo di tale importo, quindi ripeti. So che è difficile da accettare: i programmi possono passare gran parte del tempo a fare cose che (a ben vedere) sono totalmente inutili. Ma ecco il mio esempio canonico .
Mike Dunlavey,

6

Dipende dalla fase di sviluppo in cui ti trovi, quando inizi a scrivere qualcosa, le micro-ottimizzazioni non dovrebbero essere prese in considerazione in quanto otterrai maggiori guadagni prestazionali usando buoni algoritmi di quelli che stai usando microottimizzazioni. Inoltre, considera ciò che stai sviluppando poiché le applicazioni sensibili al tempo vedranno più benefici dalle considerazioni sulla micro ottimizzazione rispetto alle applicazioni aziendali generiche.

Se stai testando ed estendendo il software, le micro-ottimizzazioni probabilmente ti danneggeranno, tendono a rendere il codice più difficile da leggere e persino a introdurre il loro set unico di bug che devono essere corretti insieme a qualsiasi altra cosa che debba essere riparata.

Se stai effettivamente ricevendo reclami dagli utenti riguardo al codice lento, potrebbe valere la pena considerarli, ma solo se tutto il resto è stato risolto, vale a dire:

  • Il codice è ben scritto?
  • L'applicazione è in grado di accedere ai propri dati senza problemi?
  • È possibile utilizzare un algoritmo migliore?

Se a tutte queste domande è stata data una risposta e si verificano ancora problemi di prestazioni, potrebbe essere il momento di iniziare a utilizzare le micro-ottimizzazioni nel codice, ma è probabile che altre modifiche (ad es. Codice migliore, algoritmo migliore, ecc.) Ti metteranno in rete più di un guadagno in termini di prestazioni rispetto a una micro ottimizzazione.


5

La velocità di esecuzione è uno dei molti fattori che contribuiscono alla qualità di un programma. Spesso la velocità ha una correlazione inversa con leggibilità / manutenibilità. In quasi tutti i casi, il codice deve essere leggibile dall'uomo in modo da poterlo mantenere. L'unica volta in cui la leggibilità può essere compromessa è quando la velocità è un requisito essenziale. Il requisito di rendere il codice più veloce della piena leggibilità / manutenibilità non è quasi mai applicabile, ma ci sono alcuni casi in cui lo farà. La cosa principale da ricordare è che il codice micro-ottimizzato è spesso codice confuso, quindi a meno che non ci sia un requisito definito da qualche parte, è quasi sempre il modo sbagliato di risolvere il problema. Ad esempio, l'utente non noterà quasi mai la differenza tra i tempi di esecuzione di 0,5 secondi e 1 secondo nelle operazioni CRUD, quindi non è necessario andare in un assembly-interop-hackfest per arrivare a 0,5 secondi. Sì, potrei pilotare un elicottero per lavorare e sarebbe 10 volte più veloce, ma non lo faccio a causa del prezzo e del fatto che l'elicottero è molto più difficile da pilotare.Quando micro-ottimizzi il codice inutilmente, questo è esattamente ciò che stai facendo: aggiungere inutili complessità e costi per raggiungere un obiettivo superfluo.


5

La micro-ottimizzazione è importante quando si colpisce un vincolo. La cosa a cui tieni potrebbe essere la memoria, la velocità effettiva, la latenza o il consumo di energia. Si noti che queste sono caratteristiche a livello di sistema; non è necessario (e non è possibile) ottimizzare ogni funzione in ogni modo.

È più probabile che i sistemi integrati necessitino di microottimizzazione poiché i vincoli vengono colpiti più facilmente. Tuttavia, anche lì la micro-ottimizzazione ti porta solo finora; non puoi micro-ottimizzare la tua via d'uscita da un cattivo design. Il punto su una buona progettazione in un sistema è che puoi ragionare sul sistema nel suo insieme. I componenti che necessitano di microottimizzazione devono essere esposti e ottimizzati in modo ordinato in modo da non compromettere la progettazione del sistema.

Si noti che i piccoli sistemi "incorporati" oggi possono essere abbastanza vicini ai Vaxen o ai PDP-11 di un tempo, quindi questi problemi erano più comuni. Su un moderno sistema per scopi generici che esegue un moderno calcolo commerciale generale, la micro-ottimizzazione è rara. Questo è probabilmente parte del motivo per cui tuo padre prende la posizione che fa.

Tuttavia, non importa se hai a che fare con nanosecondi, millisecondi, secondi o ore; i problemi sono gli stessi. Devono essere valutati nel contesto del sistema e di ciò che stai cercando di ottenere.

Questo è un esempio di una recente domanda a cui ho risposto su Stack Overflow per un caso in cui era necessaria la micro-ottimizzazione: codificatori video open source per un sistema incorporato .


4

Il problema più grande con la micro-ottimizzazione è che ti porta a scrivere un codice più difficile da mantenere.

Un altro problema dipende dalla configurazione del computer, a volte la tua micro-ottimizzazione potrebbe avere prestazioni peggiori rispetto alla "ottimizzazione".

Fare molte micro-ottimizzazioni ti farà perdere molto tempo a combattere contro qualcosa che non conta davvero.

Un approccio migliore consiste nel rendere un codice più pulito, più facile da mantenere e, se si verificano problemi di prestazioni, si esegue un profilo per capire cosa sta realmente rallentando il codice. E sapendo esattamente cosa è veramente male puoi risolverlo.

Non sto dicendo che non fare micro-ottimizzazioni sia una scusa per scrivere codice stupido.


4

Se inizi a preoccuparti dei millisecondi, dovresti considerare di rinunciare a PHP e utilizzare invece C o Assembly. Non che vorrei farlo, non ha senso discutere di questi numeri e usare un linguaggio di scripting. Il tuo codice scorre con questo comando che spesso comunque?

I fattori ambientali sono fuori discussione qui, quei server funzionano comunque 24 ore su 24, 7 giorni su 7 e se effettivamente elaborano qualcosa sarebbe importante solo se si tratta davvero di un'attività in esecuzione per molto tempo.

Molto probabilmente la luce nel tuo ufficio e l'energia utilizzata dai nostri computer mentre tutti scrivevamo domande e risposte, hanno consumato molta più energia di qualsiasi tipo di micro ottimizzazione che puoi ragionevolmente applicare alle tue applicazioni che mai risparmierà.


+1 per spegnere la luce o non rispondere alle domande.
Boz,

4

Dovresti scegliere l'algoritmo migliore e più semplice per l'attività. Il motivo per cui deve essere semplice è mantenere il codice leggibile. Il motivo per cui deve essere il migliore è evitare di iniziare con caratteristiche di runtime errate. Non scegliere ciecamente BubbleSort quando sai che avrai set di dati di grandi dimensioni. Va bene, tuttavia, per il tipo occasionale di 10 elementi.

POI, se i numeri di profilatura mostrano che la scelta del miglior algoritmo semplice non è stata abbastanza buona, puoi iniziare l'ottimizzazione (che di solito è il costo della leggibilità).


BubbleSort può effettivamente essere migliore di quicksort o mergesort quando i tuoi dati sono quasi ordinati con solo pochi elementi vaganti che non sono troppo lontani dalla loro destinazione finale. Per tutte le altre attività, tuttavia, è necessario utilizzare la funzione di ordinamento integrata fornita dal linguaggio di programmazione; è il modo più semplice per iniziare (e la funzione di ordinamento integrata nella maggior parte delle lingue ha buone prestazioni). BAD CONSIGLI:, start out with bad runtime characteristicnon iniziare deliberatamente con una cattiva caratteristica di runtime.
Sdraiati Ryan il

@Senti, se SAPETE che i vostri dati sono quasi ordinati e, QUINDI, potete usare il bubblesort, non state esattamente scegliendo ciecamente il vostro algoritmo ... Grazie anche per aver sottolineato l'errore di battitura.

4

L'ho già detto prima, e lo dirò qui: "L'ottimizzazione prematura è la radice di tutti i mali" . Questa dovrebbe essere una delle regole al centro della mente di ogni programmatore.

Il codice può, ad un certo punto, essere sempre più veloce di quanto non sia attualmente. A meno che tu non stia confezionando a mano un assemblaggio con un particolare chip in mente, c'è sempre qualcosa da guadagnare attraverso l'ottimizzazione. Tuttavia, a meno che NON VUOI confezionare a mano un assemblaggio per tutto ciò che fai, ci deve essere un obiettivo quantitativo, che una volta che incontri, dici "basta" e smetti di ottimizzare, anche se c'è ancora un lampante spettacolo di prestigio tu in faccia.

Il codice bello, elegante, estremamente performante è inutile se non funziona (e per "lavoro" intendo produrre l'output previsto dati tutti gli input previsti). Pertanto, la produzione di codice che funzioni dovrebbe SEMPRE essere la prima priorità. Dopo che funziona, valuti le prestazioni e, se manca, cerchi modi per renderle migliori, fino al punto in cui sono abbastanza buone.

Ci sono alcune cose che devi decidere in anticipo che influiranno sulle prestazioni; decisioni molto basilari come la lingua / runtime che userete per implementare questa soluzione. Molti di questi avranno un impatto sulle prestazioni di molti ordini di grandezza più che chiamare un metodo contro un altro. Onestamente, PHP, come linguaggio di script, è già un successo prestazionale, ma poiché pochissimi siti di script sono costruiti dal basso verso l'alto in C / C ++, è paragonabile ad altre tecnologie che probabilmente sceglieresti (Java Servlets, ASP.NET , eccetera).

Successivamente, la dimensione del messaggio I / O è il tuo killer delle prestazioni più grande successivo. L'ottimizzazione di ciò che leggi e scrivi sul disco rigido, le porte seriali, le pipe di rete, ecc. Di solito migliorerà il tempo di esecuzione del programma di molti ordini di grandezza, anche se gli algoritmi dietro le operazioni di I / O erano efficienti. Successivamente, riduci la complessità Big-O dell'algoritmo stesso e, se assolutamente necessario, puoi "micro-ottimizzare" scegliendo chiamate di metodo meno costose e prendendo altre decisioni esoteriche a livelli bassi.


2
+1 La produzione di codice che funzioni dovrebbe SEMPRE essere la prima priorità.
Boz,

2
@Keith, in realtà Knuth l'ha detto per primo, e ha detto un po 'di più.

"Fallo funzionare, quindi fallo funzionare il più velocemente possibile", Anon.
John Saunders,

1
In realtà la religione è la radice di tutti i mali, ma sto divagando.
Thomas Eding,

4

Dici che tuo padre è un programmatore in pensione. I programmatori che lavoravano nel mondo dei mainframe dovevano essere molto preoccupati per le prestazioni. Ricordo di aver studiato un'attività della Marina degli Stati Uniti in cui il loro mainframe era vincolato all'hardware a 64 KB di memoria per utente. In quel mondo di programmazione devi fare un piccolo salto.

Adesso le cose sono molto diverse e la maggior parte dei programmatori non deve preoccuparsi così tanto delle microottimizzazioni. Tuttavia, i programmatori di sistemi embedded continuano a fare e le persone del database devono ancora utilizzare il codice ottimizzato.


3

Il codice dovrebbe essere scritto per essere assolutamente chiaro su ciò che fa. Quindi, se e solo se è troppo lento, tornare indietro e accelerarlo. Il codice può sempre essere modificato per essere più veloce in seguito, se può essere compreso, ma buona fortuna cambiarlo per essere chiaro se è veloce.


3

È importante se:

1) La vita di qualcuno dipende dal tuo codice. Una funzione che impiega 25 ms per essere eseguita nel cardiofrequenzimetro di qualcuno è probabilmente una cattiva idea.

Personalmente adotto un approccio su due fronti - ci sono micro-ottimizzazioni che puoi fare che non influenzano la leggibilità - ovviamente vuoi usarle. Ma se influisce sulla leggibilità, tieni duro: non otterrai molti benefici e in realtà potrebbe richiedere più tempo per eseguire il debug a lungo termine.


2
Solo alcuni punti minori sul tuo esempio: una funzione in un cardiofrequenzimetro che impiega 25 ms non sarebbe un problema fintanto che potrebbero verificarsi altri compiti necessari con il tempo di risposta richiesto. Gli interrupt sono buoni per questo. E la latenza di 25 ms per qualcosa che sta semplicemente monitorando eventi del mondo reale per aggiornare un display per il consumo umano probabilmente non è un problema.
Jan

3

La micro-ottimizzazione è importante durante la codifica?

No, dato che ci sono piattaforme come JVM e .NET in cui il codice è scritto per una macchina virtuale e quindi cercare di ottimizzare l'esecuzione potrebbe non funzionare così bene come ciò che è ottimale sul desktop di uno sviluppatore non è necessariamente lo stesso su un server. Guarda quanto sono lontani dall'hardware alcuni di questi software di alto livello per un altro punto qui. Qualcosa da considerare è la diversità dell'hardware, quanto è realistico ottimizzare il codice per chip specifici come una CPU o GPU quando un nuovo modello uscirà probabilmente in meno di un anno?

Un'altra domanda da considerare è la prestazione misurata da quale metrica: velocità di esecuzione, memoria utilizzata nell'esecuzione, velocità di sviluppo di nuove funzionalità, dimensione della base di codice su un server in moduli compilati o decompilati, scalabilità, manutenibilità, ecc. .? Se presa abbastanza ampiamente, la domanda diventa banale, ma non sono sicuro di quanto in generale intendevi considerare le prestazioni come realmente, che possono essere praticamente qualsiasi cosa, purché possano essere misurate in qualche modo.


Alcune micro-ottimizzazioni potrebbero funzionare e alcune potrebbero non funzionare, ed è qui che ci si può chiedere quanto valga la pena eseguire tale lavoro rispetto ad altri lavori che possono essere visti come priorità molto più alte come nuove funzionalità o correzione di bug. L'altra domanda sarebbe se un aggiornamento di hardware o software potrebbe interrompere anche alcune di queste ottimizzazioni.


1
Nota che puoi assolutamente fare micro-ottimizzazioni su piattaforme come JVM e .NET, che assumono solo forme leggermente diverse. Lo stesso vale se si confronta e un compilatore C vecchio e semplice con un compilatore più moderno e altamente ottimizzante: le ottimizzazioni che l'utente può fare appariranno diverse.
Joachim Sauer,

1

Penso che ci sia una grande differenza tra buona programmazione e micro-ottimizzazione.

Se ci sono due modi per fare lo stesso compito, uno è più veloce dell'altro ed entrambi hanno la stessa leggibilità, dovresti usare il più veloce. Sempre. E questa è una buona programmazione. Non c'è motivo di non utilizzare un algoritmo migliore per risolvere un problema. E anche documentarlo è semplice: dai il nome dell'algoritmo, tutti saranno in grado di cercarlo su Google e trovare maggiori informazioni su come funziona.

E i buoni algoritmi sono già ottimizzati. Saranno veloci. Saranno piccoli. Utilizzeranno la memoria minima richiesta.

Anche se utilizzandoli il tuo programma non ha ancora queste prestazioni, puoi considerare di ottimizzarlo. E dovrai conoscere davvero la lingua per essere in grado di micro-ottimizzare.

E c'è sempre spazio per spendere più soldi per l'hardware. L'hardware è economico, i programmatori sono costosi . Non spendere troppo tempo / denaro ottimizzando quando puoi semplicemente acquistare hardware.


1

La leggibilità del codice IMHO è più importante della micro-ottimizzazione perché nella maggior parte dei casi la micro-ottimizzazione non ne vale la pena.

Articolo sulle micro-ottimizzazioni senza senso :

Come la maggior parte di noi, sono stanco di leggere post sul blog su micro-ottimizzazioni senza senso come la sostituzione di stampa con eco, ++ $ i con $ i ++ o doppie virgolette con virgolette singole. Perché? Perché il 99.999999% delle volte, è irrilevante. Perché? Perché il 99,99% delle volte, è meglio installare un acceleratore PHP come APC o aggiungere questi indici mancanti nelle colonne del database o cercare di evitare quelle 1000 richieste di database che hai sulla homepage.

print utilizza un altro codice operativo perché restituisce effettivamente qualcosa. Possiamo concludere che l'eco è più veloce della stampa. Ma un codice operativo non costa nulla, davvero niente.

Ho provato una nuova installazione di WordPress. Lo script si interrompe prima di terminare con un "Errore di bus" sul mio laptop, ma il numero di codici operativi era già di oltre 2,3 milioni. È stato detto abbastanza.

Quindi nella maggior parte dei casi la micro-ottimizzazione consente di risparmiare 1 operazione su milioni, ma peggiora la leggibilità.


1

Altre risposte sono giuste sui soldi. Ma aggiungerò un altro punto in cui si deve differenziare ciò che è l'ottimizzazione prematura / micro-ottimizzazione e la scrittura di codice performante che riflette una comprensione del comportamento dei costrutti linguaggio / framework (mi dispiace, non sono riuscito a trovare una parola per l'ultima) . L'ultima è una buona pratica di codifica e generalmente si dovrebbe fare!

Spiegherò. L'ottimizzazione errata (leggi l'ottimizzazione prematura / microscopica) non avviene quando si ottimizzano sezioni di codice senza profilatura per sapere se sono davvero i colli di bottiglia. È quando ottimizzi in base ai tuoi presupposti, ascolti e comportamenti privi di documenti. Se è documentato e fa qualcosa in modo più efficiente / logico per quanto piccolo sia, lo chiamo buona ottimizzazione . Come altri hanno affermato, entrambi hanno dei contro e quasi nessun vantaggio per quanto riguarda guadagnarti buoni affari, ma faccio comunque il secondo, non il primo, se non sconfigge totalmente la leggibilità. Sì, la leggibilità / manutenibilità è della massima importanza e riguarda il punto in cui si traccia la linea.

Ribadirò i punti sollevati da altri qui come futilità di ottimizzazioni sia positive che negative:

  1. Le dipendenze da un problema specifico possono cambiare e qualsiasi tempo impiegato per l'ottimizzazione prima di completare la sezione logica dell'applicazione è una perdita di tempo. Intendo ottimizzare in una fase relativamente precoce. Oggi hai un List<T>e quando la tua app viene spedita dovevi cambiarlo LinkedList<T>e ora tutto il benchmarking era una perdita di tempo e fatica.

  2. Principalmente il vero collo di bottiglia della tua applicazione (leggi come differenza misurabile) potrebbe essere il 5% del tuo codice (principalmente quelli sql) e l'ottimizzazione dell'altro 95% non offre alcun vantaggio ai tuoi clienti.

  3. Di solito un codice "tecnicamente" più performante significa più verbosità che a sua volta significa più codice soggetto a errori che a sua volta significa maggiore manutenibilità e più tempo speso che a sua volta significa che guadagni meno soldi.

  4. L'impronta di carbonio risparmiata per tutto il mondo con un aumento delle prestazioni dell'1% viene facilmente ridotta dai gas serra che il tuo team dovrà emettere durante il debug e il mantenimento di quel codice.

Gli aspetti negativi di una cattiva ottimizzazione in particolare sono:

  1. Non ti dà spesso le prestazioni che ti aspetti. Vedi questa domanda su SO, dove le ottimizzazioni sono andate male . In effetti può avere effetti negativi. Questo è il problema con un comportamento non documentato.

  2. Per lo più compilatori moderni lo faranno comunque per te.

Darò alcuni esempi di ottimizzazione cattiva e buona:

Il cattivo -

  1. uso di tipi interi più piccoli invece di Int32.

  2. ++i usato al posto di i++

  3. forinvece di foreach(il peggio che ho visto, sconfigge totalmente la logica)

  4. evitando variabili chiuse

    string p;
    foreach (var item in collection)
        p = ...;
    
  5. usando charinvece di stringa durante la concatenazione di stringhe, come:

    string me = 'i' + "me myself"; // something along that line - causes boxing
    

Il buono (dal mondo .NET. Dovrebbe essere autoesplicativo) -

  1. Doppia ricerca

    if (Dictionary<K, V>.TryGetValue(K, out V))
        do something with V
    

    invece di

    if (Dictionary<K, V>.ContainsKey(K))
        do something with Dictionary<K, V>[K]
    
  2. Caricali tutti

    DirectoryInfo.EnumerateFiles();
    

    invece di

    DirectoryInfo.GetFiles();
    
  3. Casting in due fasi:

    s = o as string;
    if (s != null)
        proceed
    

    invece di

    if (o is string)
        s = (string)o;
    
  4. Se l'ordine non ha importanza

    if (counter < X || expensiveFunction())
    

    invece di

    if (expensiveFunction() || counter < X)
    
  5. Boxe

    void M<T>(T o) //avoids boxing
    {
    
    }
    

    invece di

    void M(object o)
    {
    
    }
    

Se mi chiedi se questi offrono notevoli vantaggi in termini di prestazioni, direi di no. Ma suggerirei di usarli perché deriva dalla comprensione del comportamento di questi costrutti. Perché effettuare due chiamate quando puoi fare solo 1? Da un punto di vista filosofico la sua buona pratica di codifica. E 1 e 3 sono leggermente meno leggibili anche in termini rigorosi, ma vincono la leggibilità? No, non molto, quindi uso. Ora questa è la chiave: mantenere un discreto rapporto prestazioni / leggibilità. E quando è quello, si tratta di dove si disegna la linea.


1

"Ne vale la pena" ha bisogno di un contesto, ad esempio quanto sia più semplice scrivere, leggere e mantenere rispetto a quanto più velocemente rende l' utente notevolmente più reattivo, interattivo, richiedendo meno tempo per l'attesa.

Risparmiare qualche soldo per acquistare una lattina di soda non mi farà molto bene se devo percorrere una distanza per salvare quei penny, soprattutto dato che al giorno d'oggi raramente bevo soda. Risparmiare qualche soldo per lattina con un acquisto di un milione di lattine di bibite potrebbe essere un grosso problema.

Nel frattempo risparmiando qualche soldo quando due persone sono proprio accanto a me e una offre esattamente la stessa cosa per qualche soldo in meno e l'altra no, e scelgo quella più costosa perché mi piace che il loro cappello sembri meglio un caso sciocco di pessimizzazione.

Ciò che trovo spesso le persone che chiamano "micro-ottimizzazioni" sembrano curiosamente prive di misurazioni, contesto e discussione da parte dell'utente, quando dovrebbero assolutamente essere tutte e tre le considerazioni su tali ottimizzazioni se non sono banali da applicare. Per me una corretta micro-ottimizzazione in questi giorni si riferisce a cose come layout di memoria e schemi di accesso, e sebbene possano sembrare "micro" a fuoco, non sono micro effetti.

Sono riuscito, non molto tempo fa, a ridurre un'operazione da 24 secondi a 25 millisecondi (circa 960 volte più veloce), con output identici (garantiti da test automatizzati), senza cambiare la complessità algoritmica, per lo skinning di diffusione del calore volumetrico, attraverso "micro-ottimizzazioni" (la più grande delle quali derivava da un cambiamento nel layout della memoria che lo ha portato a circa 2 secondi, poi il resto erano cose come SIMD e ulteriori analisi dei mancati cache nella VTune e qualche ulteriore riorganizzazione del layout della memoria).

Wolfire spiega la tecnica qui e ha lottato con il tempo richiesto: http://blog.wolfire.com/2009/11/volumetric-heat-diffusion-skinning/

La mia implementazione è riuscita a riuscire a farlo in millisecondi mentre stava lottando per ridurlo a meno di un minuto: inserisci qui la descrizione dell'immagine

Dopo aver "micro-ottimizzato" da 24 secondi a 25 ms, questo è stato un punto di svolta nel flusso di lavoro. Ora gli artisti possono cambiare i loro rig in tempo reale a oltre 30 FPS senza aspettare 24 secondi ogni volta che hanno apportato piccole modifiche al loro rig. E questo in realtà ha cambiato l'intero design del mio software poiché non avevo più bisogno di barra di avanzamento e cose di questo tipo, è diventato tutto interattivo. Quindi quella potrebbe essere una "micro-ottimizzazione" nel senso che tutti i miglioramenti sono arrivati ​​senza alcun miglioramento della complessità algoritmica, ma è stata in effetti una "mega-ottimizzazione" che ha reso quello che precedentemente era un processo doloroso, non interattivo in uno in tempo reale, interattivo che ha completamente cambiato il modo in cui gli utenti lavoravano.

Misurazioni, requisiti dell'utente finale, contesto

Mi è piaciuto molto il commento di Robert qui e forse non sono riuscito a esprimere il punto che volevo:

Bene, dai. Nessuno sosterrà che questo tipo di cambiamento non "vale la pena". Sei stato in grado di dimostrare un beneficio tangibile; molte cosiddette microottimizzazioni non possono.

Questa è, nonostante lavori in un campo molto critico in termini di prestazioni con requisiti spesso in tempo reale, l'unica volta che considero qualsiasi micro-ottimizzazione che richiede di andare fuori strada.

E sottolineerei non solo le misurazioni ma anche il suo lato utente. Sono strano nel fatto che sono arrivato nel mio campo attuale (e precedentemente con gamedev) come utente / fan prima, sviluppatore secondo. Quindi non sono mai stato così eccitato dalle solite cose che eccitano i programmatori come risolvere enigmi tecnici; Li ho trovati un peso, ma li sopporterei attraverso il sogno dell'utente che condividevo con altri utenti. Ma ciò mi ha aiutato a essere sicuro che se stavo ottimizzando qualcosa, avrebbe avuto un impatto reale sugli utenti con vantaggi reali. È la mia protezione contro la microottimizzazione senza scopo.

Questo in realtà è importante quanto il profiler secondo me, perché avevo colleghi che facevano cose come micro-ottimizzare la suddivisione di un cubo in un miliardo di sfaccettature solo per soffocare su modelli di produzione del mondo reale come personaggi e veicoli. Il loro risultato è stato impressionante in un certo senso di "demo tecnologica", ma quasi inutile per gli utenti reali, poiché si trattava di profilare, misurare e confrontare casi che non si allineavano ai casi d'uso reali. Quindi è così importante capire prima cosa è importante per gli utenti, sia imparando a pensare e usare il software come uno o collaborando con loro (idealmente entrambi, ma almeno collaborando con loro).


2
Bene, dai. Nessuno sosterrà che questo tipo di cambiamento non "vale la pena". Sei stato in grado di dimostrare un beneficio tangibile; molte cosiddette microottimizzazioni non possono.
Robert Harvey,

1
@RobertHarvey Era una specie di punto speravo di fare, dal momento che ciò che alcuni chiamano "micro-ottimizzazione" non è necessariamente microscopica in effetti, ma è così dipendente dal contesto, misure, ecc issetvs. strlensembra più minuscola a fuoco assente il contesto e le misurazioni. MrGreen
Dragon Energy il

1
@RobertHarvey Speravo di dire, forse anche se indirettamente, che se c'è un contesto negativo alle "micro-ottimizzazioni", è il tipo che tende a essere privo di quelle misurazioni, contesti e bisogni dell'utente finale. Potrei andare avanti anche sull'ultimo caso dato che avevo un collega che ottimizzava l'inferno di qualcosa che era bello, tranne che nessuno lo usava. Penso anche che una corretta ottimizzazione richieda una certa comprensione da parte dell'utente, altrimenti potremmo profilare e mettere a punto cose di cui gli utenti non si preoccupano.
Dragon Energy il

1
Alcune ottimizzazioni sono guidate da necessità urgenti, mentre altre sono guidate dalla curiosità (ricerca intellettuale e avventurismo). Abbiamo bisogno di entrambi. Nella storia di Dragon Energy, probabilmente non si trattava di un "bisogno urgente", poiché gli artisti apparentemente non si lamentavano rumorosamente di non vedere alcun risultato di rendering fino a 24 secondi dopo ogni modifica. In effetti, gli utenti potrebbero non sapere quanto velocemente avrebbe potuto essere, fino a quando un programmatore non ha investito in tutti gli sforzi per battere il record di velocità. Limitare noi stessi alla domanda guidata ha senso dal punto di vista commerciale, ma così facendo mancheranno alcune incredibili opportunità di ottimizzazione o cambi di gioco.
rwong,

1
Parlando di senso degli affari, c'è anche il problema della monetizzazione. Ogni mossa (ad es. Un programmatore che lavora sull'ottimizzazione delle prestazioni) costa denaro e il costo deve essere recuperato per avere senso per il business. Pertanto, ci si deve chiedere se il miglioramento della velocità che cambia il gioco può essere "venduto", o quanti soldi sarebbero "salvati", se il programmatore deve ottenere l'approvazione da un direttore aziendale.
rwong

0

Lo metterò in questo modo: la micro-ottimizzazione è un processo di ottimizzazione di qualcosa che non è affatto un collo di bottiglia. Ad esempio, se il tuo programma chiama due funzioni A e B e A impiega 100 millisecondi per completare e B impiega 2 microsecondi e continui a ottimizzare la funzione B. Non solo non è importante, è assolutamente sbagliato. Ma l'ottimizzazione della funzione B si chiama ottimizzazione e non micro-ottimizzazione. L'importanza dell'ottimizzazione dipende. Di 'che non hai nient'altro da fare e che il tuo programma è privo di bug, quindi sì, è importante. Ma generalmente hai delle priorità. Diciamo che devi aggiungere / scrivere la funzione C. Se pensi che scrivere la funzione C ti farà guadagnare più denaro che rendere il tuo programma più veloce senza quella funzionalità, allora vai per l'ottimizzazione. Altrimenti perseguire la funzionalità. Anche, programmatori esperti focalizzati sulle prestazioni non trascorrono molto tempo a ottimizzare, scrivono solo programmi veloci. Di almeno sanno quali strumenti usare e cosa non fare per passare anni facendo ottimizzazioni insignificanti (leggi micro).


questo post è piuttosto difficile da leggere (wall of text). Ti dispiacerebbe modificarlo in una forma migliore?
moscerino del
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.