L'ottimizzazione prematura è davvero la radice di tutti i mali?


215

Un mio collega oggi ha impegnato una classe chiamata ThreadLocalFormat, che sostanzialmente spostava istanze di classi Java Format in un thread locale, dal momento che non sono thread-safe e "relativamente costosi" da creare. Ho scritto un test rapido e ho calcolato che avrei potuto creare 200.000 istanze al secondo, gli ho chiesto se ne stava creando tanti, a cui ha risposto "da nessuna parte vicino a tanti". È un grande programmatore e tutti i membri del team sono altamente qualificati, quindi non abbiamo problemi a comprendere il codice risultante, ma è stato chiaramente un caso di ottimizzazione laddove non è necessario. Ha sostenuto il codice su mia richiesta. Cosa ne pensi? È un caso di "ottimizzazione prematura" e quanto è grave?


23
Penso che sia necessario distinguere tra ottimizzazione prematura e ottimizzazione non necessaria. Per me prematuro suggerisce "troppo presto nel ciclo di vita" laddove un inconscio suggerisce "non aggiunge un valore significativo". IMO, il requisito per l'ottimizzazione tardiva implica un design scadente.

110
Sì, ma il male è un polinomio e ha molte radici, alcune delle quali sono complesse.
dan_waterworth,

7
Dovresti considerare che Knuth scrisse questo 1974. Negli anni Settanta non era così facile scrivere programmi lenti come lo è oggi. Ha scritto pensando a Pascal e non a Java o PHP.
ceving

4
No. La radice di tutto il male è l'avidità.
Tulains Córdova,

12
@ceving Negli anni 70 era facile come oggi scrivere programmi lenti. Se scegli l'algoritmo sbagliato o la struttura dei dati sbagliata, allora BAM! Cattive prestazioni in tutto il luogo. Si potrebbe discutere al contrario. Oggi ci sono molti più strumenti e dovrebbe essere ingiustificabile che un programmatore scriva ancora software che subisce l'operazione di salvataggio più basilare. Il parallelismo è diventato quasi un prodotto e ancora soffriamo. Le prestazioni lente non possono essere attribuite al linguaggio o allo strumento, alla CPU o alla memoria. È un delicato equilibrio di così tante cose ed è per questo che è quasi impossibile ottimizzare in anticipo.
Alex,

Risposte:


322

È importante tenere presente l'intero preventivo:

Dobbiamo dimenticare le piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali. Tuttavia non dovremmo rinunciare alle nostre opportunità in quel 3% critico.

Ciò significa che, in assenza di problemi di prestazioni misurati, non è necessario ottimizzare perché si ritiene di ottenere un miglioramento delle prestazioni. Ci sono ovvie ottimizzazioni (come non eseguire la concatenazione di stringhe all'interno di un circuito chiuso) ma tutto ciò che non è un'ottimizzazione banalmente chiara dovrebbe essere evitato fino a quando non può essere misurato.

I maggiori problemi con "l'ottimizzazione prematura" sono che può introdurre bug imprevisti e può essere un enorme spreco di tempo.


7
Essendo di Donald Knuth, non sarei sorpreso se avesse qualche prova a sostegno. A proposito, Src: Programmazione strutturata con andare a Dichiarazioni, ACM Journal Computing Surveys, Vol 6, No. 4, Dec. 1974. p.268. citeseerx.ist.psu.edu/viewdoc/…
mctylr

28
... Un buon programmatore non si crogiolerà nella compiacenza di tale ragionamento, sarà saggio guardare attentamente il codice critico; ma solo dopo che quel codice è stato identificato (resto
dell'offerta

21
Oggi un utente di 20k rappresentanti mi ha detto che usare un'ottimizzazione prematura HashSetanziché una Listera prematura. Il caso d'uso in questione era una raccolta inizializzata staticamente il cui unico scopo era quello di fungere da tabella di consultazione. Non credo di sbagliarmi nel dire che esiste una distinzione nella scelta dello strumento giusto per il lavoro rispetto all'ottimizzazione precoce. Penso che il tuo post confermi questa filosofia: There are obvious optimizations...anything that isn't trivially clear optimization should be avoided until it can be measured.l'ottimizzazione di un HashSet è stata accuratamente misurata e documentata.
schiaccia il

9
@crush: sì: Setè anche più semanticamente corretto e informativo di List, quindi c'è più dell'aspetto di ottimizzazione.
Erik Allik,

7
Vorrei aggiungere che l'ottimizzazione prematura non deve essere confusa con la progettazione dell'intera architettura dell'applicazione per funzionare velocemente in generale, scalare ed essere facilmente ottimizzabile.
Erik Allik,

111

Le micro ottimizzazioni premature sono la radice di tutti i mali, perché le micro ottimizzazioni tralasciano il contesto. Non si comportano quasi mai nel modo previsto.

Quali sono alcune buone ottimizzazioni iniziali in ordine di importanza:

  • Ottimizzazioni architettoniche (struttura dell'applicazione, il modo in cui è strutturata e stratificata)
  • Ottimizzazioni del flusso di dati (all'interno e all'esterno dell'applicazione)

Alcune ottimizzazioni del ciclo di sviluppo intermedio:

  • Strutture di dati, introducono nuove strutture di dati con prestazioni migliori o costi generali inferiori, se necessario
  • Algorithms (ora è un buon momento per iniziare a decidere tra quicksort3 e heapsort ;-))

Alcune ottimizzazioni del ciclo di sviluppo finale

  • Trovare hotpots di codice (loop stretti, che dovrebbero essere ottimizzati)
  • Ottimizzazioni basate sulla profilazione di parti computazionali del codice
  • Le micro ottimizzazioni possono essere eseguite ora come vengono eseguite nel contesto dell'applicazione e il loro impatto può essere misurato correttamente.

Non tutte le ottimizzazioni iniziali sono malvagie, le micro ottimizzazioni sono cattive se eseguite nel momento sbagliato nel ciclo di vita dello sviluppo , poiché possono influenzare negativamente l'architettura, possono influire negativamente sulla produttività iniziale, possono essere irrilevanti dal punto di vista delle prestazioni o persino avere un effetto dannoso alla fine di sviluppo a causa di diverse condizioni ambientali.

Se le prestazioni sono preoccupanti (e dovrebbero sempre esserlo) pensare sempre in grande . Le prestazioni sono un quadro più ampio e non riguardano cose come: dovrei usare int o long ? Scegli Top Down quando lavori con prestazioni anziché Bottom Up .


"Ottimizzazione: il tuo peggior nemico", di Joseph M. Principiante: flounder.com/optimization.htm
Ron Ruble,

53

l'ottimizzazione senza prima misurazione è quasi sempre prematura.

Credo che sia vero in questo caso, e anche nel caso generale.


Qui qui! L'ottimizzazione non considerata rende il codice non gestibile ed è spesso causa di problemi di prestazioni. ad es. multi-thread di un programma perché immagini che possa aiutare le prestazioni, ma la vera soluzione sarebbe stata quella di più processi che ora sono troppo complessi da implementare.
James Anderson,

a meno che non sia documentato.
nawfal,

Sì. completamente d'accordo. Deve prima essere misurato. Non è possibile sapere dove si trovano i colli di bottiglia finché non si verifica qualcosa da un capo all'altro e si misura ciascuno dei passaggi.
Oliver Watkins,

Le misure possono mentire. Ho visto specialisti esperti passare settimane a leggere tracce e eseguire profili per colpire un muro dove pensavano che non ci fosse altro da guadagnare. Poi ho letto l'intero codice e in poche ore ho apportato alcune modifiche olistiche per ottenere un miglioramento di 10 volte. I profili non mostravano hot-path perché l'intero codice era mal progettato. Ho anche visto i profiler rivendicare percorsi rapidi in cui non avrebbero dovuto esserci. Una persona che "misura" avrebbe ottimizzato l'hotpath, ma avrebbe dovuto rendersi conto che l'hotpath era un sintomo di un altro codice scadente.
Bengie,

42

L'ottimizzazione è "malvagia" se causa:

  • codice meno chiaro
  • molto più codice
  • codice meno sicuro
  • tempo sprecato per il programmatore

Nel tuo caso, sembra che un po 'di tempo del programmatore fosse già trascorso, il codice non era troppo complesso (un'ipotesi dal tuo commento che tutti nel team sarebbero in grado di capire) e il codice è un po' più a prova di futuro (essendo thread sicuro ora, se ho capito la tua descrizione). Sembra solo un po 'malefico. :)


4
Solo se il costo, in termini di punti elenco, è maggiore del valore ammortizzato erogato. Spesso la complessità introduce valore e in questi casi è possibile incapsularla in modo tale da soddisfare i propri criteri. Inoltre viene riutilizzato e continua a fornire più valore.

1
Questi primi due punti sono i principali per me, il quarto è una conseguenza negativa dell'ottimizzazione prematura. In particolare, è una bandiera rossa ogni volta che vedo qualcuno reimplementare funzionalità da una libreria standard. Ad esempio, una volta ho visto qualcuno implementare routine personalizzate per la manipolazione delle stringhe perché era preoccupato che i comandi integrati fossero troppo lenti.
jhocking

8
Rendere sicuro il thread di codice non è ottimizzazione.
mattnz,

38

Sono sorpreso che questa domanda abbia 5 anni, eppure nessuno ha pubblicato più di ciò che Knuth aveva da dire di un paio di frasi. La coppia di paragrafi che circonda la famosa citazione lo spiega abbastanza bene. Il documento che viene citato si chiama " Programmazione strutturata con go to dichiarazioni ", e mentre ha quasi 40 anni, parla di una controversia e di un movimento di software che non esistono più, e ha esempi in linguaggi di programmazione che molte persone non hanno mai sentito parlare, una quantità sorprendentemente grande di ciò che ha detto vale ancora.

Ecco una citazione più grande (da pagina 8 del pdf, pagina 268 nell'originale):

Il miglioramento della velocità dall'Esempio 2 all'esempio 2a è solo del 12% circa e molte persone lo dichiarerebbero insignificante. La saggezza convenzionale condivisa da molti degli odierni ingegneri del software richiede di ignorare l'efficienza nel piccolo; ma credo che questa sia semplicemente una reazione eccessiva agli abusi che vedono essere praticati da programmatori pazzi di soldi, che non possono eseguire il debug o mantenere i loro programmi "ottimizzati". Nelle discipline ingegneristiche consolidate un miglioramento del 12%, facilmente ottenibile, non è mai considerato marginale; e credo che lo stesso punto di vista dovrebbe prevalere nell'ingegneria del software. Ovviamente non mi preoccuperei di fare tali ottimizzazioni con un solo lavoro, ma quando si tratta di preparare programmi di qualità, non voglio limitarmi a strumenti che mi negano tali efficienze.

Non c'è dubbio che il graal dell'efficienza porti ad abusi. 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 impatto negativo quando si considerano il debug e la manutenzione. Noi dovremmo dimenticare piccole efficienze, dire circa il 97% del tempo: l'ottimizzazione prematura è la radice di tutti i mali.

Tuttavia non dovremmo rinunciare alle nostre opportunità in quel 3% critico. Un buon programmatore non si crogiolerà in tale compiacimento, sarà saggio guardare attentamente il codice critico; ma solo dopo che quel codice è stato identificato. Spesso è un errore dare giudizi a priori su quali parti di un programma sono veramente critiche, poiché l'esperienza universale dei programmatori che hanno utilizzato strumenti di misurazione è stata che le loro ipotesi intuitive falliscono.

Un altro aspetto positivo della pagina precedente:

Il mio stile di programmazione è ovviamente cambiato nell'ultimo decennio, in base alle tendenze dei tempi (ad esempio, non sono più così complicato e uso meno go to's), ma il grande cambiamento nel mio stile è dovuto a questo fenomeno del circuito interno. Ora guardo con occhio estremamente itterico ogni operazione in un ciclo interno critico, cercando di modificare il mio programma e la struttura dei dati (come nel passaggio dall'Esempio 1 all'Esempio 2) in modo che alcune operazioni possano essere eliminate. Le ragioni di questo approccio sono le seguenti: a) non ci vuole molto, poiché il circuito interno è corto; b) il payoff è reale; e c) posso quindi permettermi di essere meno efficiente nelle altre parti dei miei programmi, che sono quindi più leggibili e più facilmente scritte e debug.


20

Ho visto spesso questa citazione usata per giustificare ovviamente un codice o codice errato che, sebbene le sue prestazioni non siano state misurate, potrebbe probabilmente essere reso più velocemente abbastanza facilmente, senza aumentare le dimensioni del codice o comprometterne la leggibilità.

In generale, penso che le micro ottimizzazioni iniziali possano essere una cattiva idea. Tuttavia, le macro-ottimizzazioni (cose come la scelta di un algoritmo O (log N) invece di O (N ^ 2)) sono spesso utili e dovrebbero essere fatte in anticipo, poiché potrebbe essere dispendioso scrivere un algoritmo O (N ^ 2) e poi buttalo via completamente a favore di un approccio O (log N).

Nota che le parole potrebbero essere : se l'algoritmo O (N ^ 2) è semplice e facile da scrivere, puoi buttarlo via in seguito senza troppi sensi di colpa se risulta troppo lento. Ma se entrambi gli algoritmi sono allo stesso modo complessi o se il carico di lavoro previsto è così grande che sai già che avrai bisogno di quello più veloce, l'ottimizzazione anticipata è una decisione ingegnosa che ridurrà il carico di lavoro totale nel lungo periodo.

Quindi, in generale, penso che l'approccio giusto sia quello di scoprire quali sono le tue opzioni prima di iniziare a scrivere codice e scegliere consapevolmente l'algoritmo migliore per la tua situazione. Ancora più importante, la frase "l'ottimizzazione prematura è la radice di tutti i mali" non è una scusa per l'ignoranza. Gli sviluppatori di carriera dovrebbero avere un'idea generale di quanto costano le operazioni comuni; dovrebbero sapere, per esempio,

  • che le stringhe costano più dei numeri
  • che le lingue dinamiche sono molto più lente delle lingue tipicamente statiche
  • i vantaggi degli elenchi array / vettori rispetto agli elenchi collegati e viceversa
  • quando usare una tabella hash, quando usare una mappa ordinata e quando usare un heap
  • che (se funzionano con dispositivi mobili) "double" e "int" hanno prestazioni simili sui desktop (FP potrebbe anche essere più veloce) ma "double" potrebbe essere cento volte più lento su dispositivi mobili di fascia bassa senza FPU;
  • che il trasferimento di dati su Internet è più lento dell'accesso all'HDD, gli HDD sono molto più lenti della RAM, la RAM è molto più lenta della cache e dei registri L1 e le operazioni su Internet possono bloccarsi indefinitamente (e fallire in qualsiasi momento).

E gli sviluppatori dovrebbero avere familiarità con una cassetta degli attrezzi di strutture dati e algoritmi in modo da poter utilizzare facilmente gli strumenti giusti per il lavoro.

Avere molta conoscenza e una cassetta degli attrezzi personale ti consente di ottimizzare quasi senza sforzo. Fare un grande sforzo in un'ottimizzazione che potrebbe non essere necessaria è male (e ammetto di cadere in quella trappola più di una volta). Ma quando l'ottimizzazione è semplice come scegliere un set / hashtable invece di un array o memorizzare un elenco di numeri in double [] anziché in string [], allora perché no? Potrei essere in disaccordo con Knuth qui, non ne sono sicuro, ma penso che stesse parlando di ottimizzazione di basso livello mentre sto parlando di ottimizzazione di alto livello.

Ricorda, quella citazione è originaria del 1974. Nel 1974 i computer erano lenti e la potenza di calcolo era costosa, il che ha dato ad alcuni sviluppatori la tendenza a ottimizzare eccessivamente, riga per riga. Penso che sia quello a cui Knuth stava spingendo. Non stava dicendo "non preoccuparti per le prestazioni", perché nel 1974 sarebbe stato un discorso folle. Knuth stava spiegando come ottimizzare; in breve, si dovrebbe concentrarsi solo sui colli di bottiglia e prima di farlo è necessario eseguire misurazioni per trovare i colli di bottiglia.

Si noti che non è possibile trovare i colli di bottiglia fino a quando non si è scritto un programma su misura, il che significa che alcune decisioni sulle prestazioni devono essere prese prima che esista qualcosa da misurare. A volte queste decisioni sono difficili da cambiare se le sbagli. Per questo motivo, è bene avere un'idea generale di ciò che costa in modo da poter prendere decisioni ragionevoli quando non sono disponibili dati concreti.

Quanto precoce da ottimizzare e quanto preoccuparsi delle prestazioni dipendono dal lavoro. Quando scrivi script che eseguirai solo poche volte, preoccuparti delle prestazioni è di solito una completa perdita di tempo. Ma se lavori per Microsoft o Oracle e stai lavorando a una libreria che migliaia di altri sviluppatori useranno in migliaia di modi diversi, potrebbe pagare per ottimizzare l'inferno, in modo da poter coprire tutti i diversi utilizzare i casi in modo efficiente. Tuttavia, la necessità di prestazioni deve essere sempre bilanciata dalla necessità di leggibilità, manutenibilità, eleganza, estensibilità e così via.


2
Amen. Oggigiorno l'ottimizzazione prematura viene lanciata in modo troppo liberale da persone che cercano di giustificare l'uso dello strumento sbagliato per il lavoro. Se conosci lo strumento giusto per il lavoro in anticipo, allora non ci sono scuse per non usarlo.
schiaccia il

13

Personalmente, come spiegato in un thread precedente , non credo che l'ottimizzazione precoce sia negativa in situazioni in cui sai che colpirai problemi di prestazioni. Ad esempio, scrivo software di modellazione e analisi di superfici, dove mi occupo regolarmente di decine di milioni di entità. Pianificare prestazioni ottimali in fase di progettazione è di gran lunga superiore all'ottimizzazione tardiva di un progetto debole.

Un'altra cosa da considerare è come la tua applicazione verrà ridimensionata in futuro. Se si considera che il codice avrà una lunga durata, anche l'ottimizzazione delle prestazioni in fase di progettazione è una buona idea.

Nella mia esperienza, l'ottimizzazione tardiva offre premi modesti a un prezzo elevato. L'ottimizzazione in fase di progettazione, attraverso la selezione dell'algoritmo e la modifica, è decisamente migliore. A seconda del profiler per capire come funziona il tuo codice non è un ottimo modo per ottenere codice ad alte prestazioni, dovresti saperlo in anticipo.


Questo è certamente corretto. Immagino che l'ottimizzazione prematura avvenga quando il codice viene reso più complesso / difficile da comprendere per vantaggi poco chiari, in un modo che ha solo un impatto locale (il design ha un impatto globale).
Paul de Vrieze,

2
Si tratta di definizioni. Prendo l'ottimizzazione come progettazione e scrittura del codice per eseguire in modo ottimale. La maggior parte qui sembra trattarlo come un hacking con il codice una volta scoperto che non è abbastanza veloce o efficiente. Passo molto tempo a ottimizzare, di solito durante la progettazione.

3
Ottimizza il design all'inizio, ottimizza il codice alla fine.
BCS

Sei abbastanza corretto nel tuo caso, tuttavia per la maggior parte dei programmatori, credono che colpiranno i problemi di prestazioni, ma in realtà non lo faranno mai. Molti si preoccupano delle prestazioni quando hanno a che fare con 1000 entità, quando un test di base sui dati mostrerebbe che le prestazioni vanno bene fino a quando non colpiscono 1000000 entità.
Toby Allen,

1
"La pianificazione di prestazioni ottimali in fase di progettazione è di gran lunga superiore all'ottimizzazione tardiva di un progetto debole" e "l'ottimizzazione tardiva offre scarsi premi a un prezzo elevato" molto ben messo! Probabilmente non è vero per il 97% di tutti i sistemi prodotti, ma lo è per molti - sconcertantemente molti sistemi.
Olof Forshell

10

In effetti ho imparato che la non ottimizzazione prematura è più spesso la radice di tutti i mali.

Quando le persone scrivono software, inizialmente avranno problemi, come instabilità, funzionalità limitate, scarsa usabilità e cattive prestazioni. Tutti questi di solito vengono risolti quando il software matura.

Tutti questi, tranne le prestazioni. A nessuno sembra interessare la performance. Il motivo è semplice: se un software si arresta in modo anomalo, qualcuno risolverà il bug e il gioco è fatto, se manca una funzione, qualcuno lo implementerà e fatto, se il software ha cattive prestazioni non è in molti casi dovuto alla mancanza di microottimizzazione, ma a causa della cattiva progettazione e nessuno toccherà la progettazione del software. MAI.

Guarda Bochs. È lento come l'inferno. Sarà mai più veloce? Forse, ma solo nell'intervallo di qualche percento. Non otterrà mai prestazioni paragonabili a software di virtualizzazione come VMWare o VBox o persino QEMU. Perché è lento dal design!

Se il problema di un software è che è lento, allora perché è MOLTO lento e questo può essere risolto solo migliorando le prestazioni di una moltitudine. + 10% semplicemente non renderà veloce un software lento. E di solito non otterrai più del 10% con ottimizzazioni successive.

Quindi, se le prestazioni sono QUALSIASI importanti per il tuo software, dovresti tenerne conto fin dall'inizio, al momento della progettazione, invece di pensare "oh sì, è lento, ma possiamo migliorarlo in seguito". Perché non puoi!

So che non si adatta al tuo caso specifico, ma risponde alla domanda generale "L'ottimizzazione prematura è davvero la radice di tutto il male?" - con un chiaro NO.

Ogni ottimizzazione, come qualsiasi funzione, ecc. Deve essere progettata con cura e implementata con cura. E ciò include una corretta valutazione di costi e benefici. Non ottimizzare un algoritmo per salvare alcuni cicli qua e là, quando non crea un guadagno misurabile delle prestazioni.

Ad esempio: puoi migliorare le prestazioni di una funzione incorporandole, eventualmente salvando una manciata di cicli, ma allo stesso tempo probabilmente aumenti le dimensioni del tuo eseguibile, aumentando le possibilità di TLB e mancate cache che costano migliaia di cicli o addirittura operazioni di paginazione, che uccideranno completamente le prestazioni. Se non capisci queste cose, la tua "ottimizzazione" può rivelarsi negativa.

L'ottimizzazione stupida è più malvagia dell'ottimizzazione "prematura", ma entrambe sono ancora migliori della non ottimizzazione prematura.


6

Esistono due problemi con PO: in primo luogo, il tempo di sviluppo utilizzato per lavori non essenziali, che potrebbe essere utilizzato per scrivere più funzionalità o correggere più bug e, in secondo luogo, il falso senso di sicurezza che il codice sta funzionando in modo efficiente. L'OP spesso comporta l'ottimizzazione del codice che non sarà il collo di bottiglia, senza tuttavia notare il codice che lo farà. Il bit "prematuro" indica che l'ottimizzazione viene eseguita prima che un problema venga identificato mediante misurazioni appropriate.

Quindi sostanzialmente, sì, sembra un'ottimizzazione prematura, ma non lo farei necessariamente a meno che non introduca dei bug - dopo tutto, ora è stato ottimizzato (!)


Intendi dire "scrivere più test" invece di "scrivere più funzioni", giusto? :)
Greg Hewgill,

1
più funzioni comportano più test :)
workmad3,

Eh si! Questo è esattamente ciò che intendevo ...
Harriyott,

2
Il codice introduce ulteriore complessità e probabilmente non verrà utilizzato universalmente. Il backup (e cose simili) mantiene pulito il codice.
Paul de Vrieze,

3

Credo sia quello che Mike Cohn chiama "gold-plating" il codice, vale a dire passare del tempo su cose che potrebbero essere carine ma non necessarie.

Ha sconsigliato.

La "placcatura in oro" di PS potrebbe essere una specie di funzionalità di campane e fischietti. Quando guardi il codice prende forma di ottimizzazione non necessaria, classi "a prova di futuro" ecc.


2
Penso che la "doratura" sia diversa dalle ottimizzazioni. Le ottimizzazioni riguardano generalmente il tentativo di ottenere le massime prestazioni mentre la "doratura" riguarda l'aggiunta di "campane e fischietti" (tutte le funzionalità extra) che non sono fondamentali per il prodotto ma hanno un aspetto gradevole.
Scott Dorman,

3

Poiché non vi è alcun problema a comprendere il codice, questo caso potrebbe essere considerato un'eccezione.

Ma in generale l'ottimizzazione porta a un codice meno leggibile e meno comprensibile e dovrebbe essere applicato solo quando necessario. Un semplice esempio - se sai che devi ordinare solo un paio di elementi - usa BubbleSort. Ma se sospetti che gli elementi possano aumentare e non sai quanto, l'ottimizzazione con QuickSort (ad esempio) non è male, ma un must. E questo dovrebbe essere considerato durante la progettazione del programma.


1
Non sono d'accordo Direi di non usare mai una specie di bolla. Quicksort è diventato uno standard defacto ed è ben compreso ed è facile da implementare come una sorta di bolla in tutti gli scenari. Il minimo comune denominatore non è più così basso;)

1
Per un numero davvero esiguo di elementi, la ricorsione richiesta per quicksort può renderla più lenta di un bubbleort decente però ... per non parlare del fatto che un bolleort è più veloce nello scenario peggiore di quicksort (vale a dire quicksorting di un elenco ordinato)
workmad3

sì, ma questo è solo un esempio di come selezionare algoritmi per esigenze diverse;)

Vero, ma avrei quicksort come ordinamento predefinito. Se pensassi che il bubbleort avrebbe migliorato le prestazioni, questa sarebbe un'ottimizzazione, non il contrario. Scelgo quicksort come predefinito perché è ben compreso e generalmente migliore.

2
La mia idea di un ordinamento predefinito è qualunque cosa mi dia la libreria (qsort (), .sort (), (sort ...), qualunque cosa).
David Thornley,

3

Ho scoperto che il problema con l'ottimizzazione prematura si verifica soprattutto quando si riscrive il codice esistente per essere più veloce. Vedo in primo luogo come potrebbe essere un problema scrivere un'ottimizzazione contorta in primo luogo, ma soprattutto vedo l'ottimizzazione prematura sollevare la sua brutta testa nel riparare ciò che non è (noto per essere) rotto.

E l'esempio peggiore di questo è ogni volta che vedo qualcuno reimplementare funzionalità da una libreria standard. Questa è una grande bandiera rossa. Ad esempio, una volta ho visto qualcuno implementare routine personalizzate per la manipolazione delle stringhe perché era preoccupato che i comandi integrati fossero troppo lenti.

Ciò si traduce in un codice che è più difficile da capire (male) e brucia molto tempo sul lavoro che probabilmente non è utile (cattivo).


3

Da una prospettiva diversa, è la mia esperienza che la maggior parte dei programmatori / sviluppatori non pianificano il successo e il "prototipo" diventa quasi sempre la versione 1.0. Ho esperienza diretta con 4 prodotti originali separati in cui il front-end di classe, sexy e altamente funzionale (fondamentalmente l'interfaccia utente) ha portato all'adozione e all'entusiasmo diffusi degli utenti. In ciascuno di questi prodotti, i problemi di prestazione hanno iniziato a insinuarsi in tempi relativamente brevi (da 1 a 2 anni), in particolare quando i clienti più grandi e più esigenti hanno iniziato ad adottare il prodotto. Molto presto le prestazioni hanno dominato l'elenco dei problemi, sebbene lo sviluppo di nuove funzionalità abbia dominato l'elenco delle priorità della gestione. I clienti sono diventati sempre più frustrati quando ogni versione ha aggiunto nuove funzionalità che suonavano alla grande ma che erano quasi inaccessibili a causa di problemi di prestazioni.

Quindi, difetti di progettazione e implementazione molto fondamentali che erano di scarsa o nessuna preoccupazione nel "proto-tipo" sono diventati importanti ostacoli per il successo a lungo termine dei prodotti (e delle aziende).

La demo del cliente può apparire e funzionare al meglio sul tuo laptop con DOM XML, SQL Express e molti dati memorizzati nella cache sul lato client. Il sistema di produzione probabilmente si arresterà in modo anomalo se si riesce.

Nel 1976 stavamo ancora discutendo dei modi ottimali per calcolare una radice quadrata o ordinare un array di grandi dimensioni e l'adagio di Don Knuth era diretto all'errore di concentrarsi sull'ottimizzazione di quel tipo di routine di basso livello nelle prime fasi del processo di progettazione piuttosto che sulla risoluzione del problema e quindi ottimizzare le aree di codice localizzate.

Quando si ripete l'adagio come scusa per non scrivere codice efficiente (C ++, VB, T-SQL o altro), o per non progettare correttamente l'archivio dati o per non considerare l'architettura del lavoro in rete, allora IMO stanno solo dimostrando un comprensione molto superficiale della vera natura del nostro lavoro. raggio


1
Haha, o quando la demo con tre utenti diventa la versione 1.0 con mille.
Olof Forshell,

1

Suppongo che dipenda da come si definisce "prematuro". Rendere veloce la funzionalità di basso livello quando scrivi non è intrinsecamente malvagio. Penso che sia un fraintendimento della citazione. A volte penso che la citazione possa fare con qualche qualifica in più. Farei eco ai commenti di m_pGladiator sulla leggibilità però.


1

La risposta è, dipende. Sosterrò che l'efficienza è un grosso problema per alcuni tipi di lavoro, come le query complesse sul database. In molti altri casi il computer sta trascorrendo la maggior parte del tempo in attesa dell'input dell'utente, quindi l'ottimizzazione della maggior parte del codice è nella migliore delle ipotesi uno spreco di sforzi e nel peggiore dei casi controproducente.

In alcuni casi è possibile progettare per efficienza o prestazioni (percepite o reali) - selezionando un algoritmo appropriato o progettando un'interfaccia utente in modo che determinate operazioni costose avvengano in background, ad esempio. In molti casi, la profilazione o altre operazioni per determinare gli hotspot ti daranno un vantaggio 10/90.

Un esempio di ciò che posso descrivere è il modello di dati che ho fatto una volta per un sistema di gestione dei casi giudiziari che conteneva circa 560 tabelle. È iniziato normalizzato ("magnificamente normalizzato" come diceva il consulente di una certa grande azienda 5) e dovevamo solo inserire quattro elementi di dati denormalizzati:

  • Una vista materializzata per supportare una schermata di ricerca

  • Una tabella gestita da trigger per supportare un'altra schermata di ricerca che non è stato possibile eseguire con una vista materializzata.

  • Una tabella di report denormalizzata (esisteva solo perché dovevamo prendere in considerazione alcuni report di throughput quando veniva bloccato un progetto di data warehouse)

  • Una tabella gestita da trigger per un'interfaccia che doveva cercare il più recente di un numero piuttosto elevato di eventi disparati all'interno del sistema.

Questo era (all'epoca) il più grande progetto J2EE in Australasia - ben oltre 100 anni di tempo per gli sviluppatori - e aveva 4 elementi denormalizzati nello schema del database, uno dei quali non vi apparteneva affatto.


1

L'ottimizzazione prematura non è la radice di TUTTO il male, questo è certo. Ci sono tuttavia degli svantaggi:

  • investi più tempo durante lo sviluppo
  • investi più tempo a testarlo
  • investi più tempo a correggere bug che altrimenti non ci sarebbero

Invece dell'ottimizzazione precoce, si potrebbero fare test di visibilità precoce, per vedere se c'è davvero bisogno di una migliore ottimizzazione.


1

La maggior parte di coloro che aderiscono al "PMO" (la citazione parziale, cioè) affermano che le ottimizzazioni devono essere basate su misurazioni e le misurazioni non possono essere eseguite fino alla fine.

È anche la mia esperienza nello sviluppo di grandi sistemi che i test delle prestazioni vengono eseguiti alla fine, mentre lo sviluppo si avvicina al completamento.

Se dovessimo seguire il "consiglio" di queste persone, tutti i sistemi sarebbero estremamente lenti. Sarebbero anche costosi perché le loro esigenze hardware sono molto maggiori di quanto inizialmente previsto.

Ho da tempo sostenuto di eseguire test delle prestazioni a intervalli regolari nel processo di sviluppo: indicherà sia la presenza di nuovo codice (dove prima non ce n'era nessuno) sia lo stato del codice esistente.

  • Le prestazioni del codice appena implementato possono essere confrontate con quelle di un codice simile esistente. Un "feeling" per le prestazioni del nuovo codice verrà stabilito nel tempo.
  • Se improvvisamente il codice esistente va in tilt, capisci che gli è successo qualcosa e puoi investigarlo immediatamente, non (molto) più tardi quando colpisce l'intero sistema.

Un'altra idea per gli animali domestici è lo strumento software a livello di blocco funzione. Man mano che il sistema viene eseguito, raccoglie informazioni sui tempi di esecuzione dei blocchi funzione. Quando viene eseguito un aggiornamento del sistema, è possibile determinare quali blocchi funzionali funzionano come nella versione precedente e quelli che si sono deteriorati. Sulla schermata di un software è possibile accedere ai dati sulle prestazioni dal menu di aiuto.

Dai un'occhiata a questo eccellente pezzo su ciò che il PMO potrebbe o non potrebbe significare.

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.