Cosa programmano oggi i micro-ottimizzatori per i programmatori? [chiuso]


14

Ai "vecchi tempi", quando avremmo copiato shareware su floppy per amici, usavamo anche un bel po 'di assemblaggio. Esisteva una pratica comune di "micro-ottimizzazione", in cui fissavi e fissavi le linee di assemblaggio fino a quando non avessi trovato il modo di esprimerlo con un minor numero di istruzioni. C'era anche un detto, che era matematicamente impossibile, che " Puoi sempre rimuovere un'altra istruzione " . Dato che cambiare le prestazioni di runtime con piccoli fattori costanti non è un grosso problema per la (maggior parte) programmazione di oggi, i programmatori stanno trasferendo questi micro- sforzi di ottimizzazione altrove?

In altre parole, una buona pratica può essere portata a uno stato estremo in cui non aggiunge più nulla di valore? E invece sta sprecando tempo?

Ad esempio: i programmatori perdono tempo generalizzando metodi privati ​​che vengono chiamati solo da un posto? Il tempo sprecato riduce i dati dei casi di test? I programmatori sono (ancora) eccessivamente preoccupati di ridurre le righe di codice?

Di seguito sono riportati due grandi esempi di ciò che sto cercando: (1) Trascorrere del tempo a trovare i nomi delle variabili giuste, anche rinominando tutto; e (2) rimuovere anche la duplicazione di codice minore e tenue.


Si noti che questo è diverso dalla domanda "Per cosa ottimizzi? ", Perché sto chiedendo cosa sembrano massimizzare gli altri programmatori, con lo stigma di queste ottimizzazioni "micro", e quindi non un uso produttivo del tempo.



@Macneil, non so per cosa gli altri programmatori micro-ottimizzano, ma non ho molto tempo per quello. Anche i miei collaboratori sono occupati (solo i miei 2 centesimi).
Giobbe

@Job: non hai mai visto qualcuno perdere tempo, cambiare il codice senza motivo? Considerati fortunato. Di seguito sono riportati due grandi esempi: nomi di variabili e duplicazione di codice minore.
Macneil,

1
La domanda, come attualmente formulata, è un miglioramento. Non riesco a rimuovere il voto ravvicinato, ma invecchierà tra qualche giorno. In realtà, la domanda sta attirando alcune risposte piuttosto buone.
Robert Harvey,

1
A proposito, qualsiasi migliore pratica può essere portata a un tale estremo da non produrre più valore.
Robert Harvey,

Risposte:


22

Formattazione del codice

Don't     get    me   wrong             ,
code      should be   consistent        & 
readable                                , 
but       some   take it         too far.

Ah sì, i buoni vecchi tipi di variabili e i nomi delle variabili hanno bisogno delle loro colonne in una serie di dichiarazioni di variabili. Oh! Hai dimenticato la riga aggiuntiva per =il quarto e gli inizializzatori!
Macneil,

[Accidenti, voterei a favore, ma il mio limite giornaliero è raggiunto ...]
Macneil,

3
I nostri professori ci hanno costretto a formattare il codice per i nostri incarichi in questo modo. Mi ci sono voluti anni per sbarazzarmi di questa abitudine.
Oliver Weiler,

Oh caro. Sulle altre risposte stavo ridendo, ma questo fa davvero male :-(
Steve314,

2
+1 Una volta ho lavorato con una libreria in cui lo sviluppatore si è rifiutato di correggere il suo codice perché ha rovinato il suo codice formattato in colonna ...
Dean Harding

20

Un giorno scrivevo molto assemblatore. Non solo i compilatori sono migliorati, ma la maggior parte dell'hardware ora ha molta logica dedicata all'esecuzione fuori codice del codice. Il vero micro-problema è la pianificazione, la maggior parte delle istruzioni del computer richiedono diversi clock di macchina per produrre un risultato e un carico di memoria che manca la cache può richiedere diverse centinaia! Quindi l'idea era di programmare altre istruzioni per fare qualcosa di utile, invece di aspettare un risultato. E le macchine moderne possono emettere diverse istruzioni per periodo di clock. Una volta che abbiamo iniziato a ottenere un'esecuzione fuori servizio HW, ho scoperto che cercare di ottenere grandi prestazioni con la codifica manuale è diventato un gioco di tazze. Innanzitutto l'HW non funzionante non eseguirà le istruzioni nel tuo ordine accuratamente realizzato, la nuova e stravagante architettura HW ha ridotto la penalità della pianificazione del software non ottimale abbastanza da consentire al compilatore di raggiungere una percentuale inferiore alle prestazioni. Ho anche scoperto che i compilatori stavano implementando trucchi noti ma che generavano complessità, come srotolare, caricare in basso, pipeline di software ecc. La linea di fondo, devi lavorare davvero molto, saltare alcuni di questi trucchi e il compilatore ti batte. Usali tutti e il numero di istruzioni dell'assemblatore necessarie aumenta di alcune volte!

Probabilmente ancora più importante, la maggior parte dei problemi di prestazioni, non riguarda le percentuali di emissione delle istruzioni, ma l'inserimento dei dati nella CPU. Come accennato in precedenza, la latenza della memoria è ora di centinaia di cicli e la CPU può eseguire diverse istruzioni per periodo di clock, quindi a meno che il programma, e in particolare le strutture di dati, siano progettati in modo tale che la frequenza di hit della cache sia eccessivamente elevata, microtuning su istruzione il livello non avrà alcun profitto. Proprio come i tipi militari dicono che i dilettanti parlano di tattiche, i professionisti parlano di logistica. La programmazione delle prestazioni è ora oltre il 90% della logistica (spostamento dei dati). E questo è difficile da quantificare, poiché la moderna gestione della memoria ha generalmente più livelli di cache e le pagine di memoria virtuale sono gestite da un'unità hardware chiamata TLB. Anche l'allineamento di indirizzi di basso livello diventa importante, poiché i trasferimenti di dati effettivi non sono in unità di byte, o anche 64 bit long-long, ma sono disponibili in unità di linee cache. Quindi la maggior parte delle macchine moderne ha hardware che tenta di prevedere quali mancano le linee della cache di cui potresti aver bisogno in un prossimo futuro ed emette prefetch automatici per metterli nella cache. Quindi la realtà è che con le moderne CPU i modelli di prestazioni sono così complessi da essere quasi incomprensibili. Anche i simulatori hardware dettagliati non possono mai eguagliare la logica esatta dei chip, quindi la messa a punto esatta è semplicemente impossibile.

C'è ancora posto per un po 'di codifica manuale. Le librerie matematiche (come ad esempio la funzione exp), così come le più importanti operazioni di algebra lineare (come la moltiplicazione della matrice) sono ancora generalmente codificate a mano da esperti che lavorano per il fornitore dell'hardware (cioè Intel o AMD o IBM), ma probabilmente solo bisogno di un paio di programmatori di assemblaggio di alto livello per mega-computer corp.


1
La codifica manuale sta diventando sempre più difficile per le persone che lavorano al di fuori dei fornitori di CPU, poiché l'attività dipende sempre più dalla conoscenza degli addetti ai lavori e dagli strumenti specifici del fornitore (compilatori e profilatori). spiral.net cerca di modellare l'ottimizzazione della CPU e automatizzare la ricerca di soluzioni ottimali.
rwong,

Molti linguaggi informatici spingono i programmatori a microottimizzare insensatamente, rendendo difficile usare la doppia precisione per i calcoli i cui risultati verranno resi float. Per qualche motivo non riesco a capire, molte persone vedono che questa è una buona cosa.
supercat

10

A volte passo (spreco?) Tempo a scegliere un buon nome per una variabile o un metodo in modo che non sia solo descrittivo con precisione, ma abbia anche un buon stile linguistico.

Va un po 'oltre quando provo a mettere l'intero lavoro (un programma) nello stesso stile linguistico. A volte la mia opinione cambia e rivedo il libro. :)

No, ci vuole così tanto tempo. È piuttosto raro. Ma mi piace mantenere la buona grammatica nei miei programmi.


3
La denominazione è difficile. Quindi dovresti riformattare un nome quando pensi a uno molto migliore. Si noti che questo cattura lo sforzo della mente e, si spera, cristallizza anche il "perché".

1
Questa è una cosa del cervello sinistro (la parte sinistra del cervello è responsabile dell'elaborazione del linguaggio). Come programmatore retto, tendo a dedicare molto meno tempo a preoccuparmi della semantica e più tempo a preoccuparmi di come tutti i pezzi si incastrano.
Jason Baker,

7
La denominazione delle variabili e dei metodi è una parte importante della manutenibilità. Si dovrebbe passare il tempo a pensare ai nomi, in modo che tra 5 anni, la persona che mantiene il codice abbia un tempo più facile con esso.
GrandmasterB,

@grandmaster: non potrei essere più d'accordo.
Robert Harvey,

4
@ brain-righters: per favore codice per i mancini, quindi posso leggere anche il tuo codice
Juan Mendes,

10

Complessità temporale. Trascorro troppo tempo a ottimizzare le cose per le prestazioni peggiori su una scala che è ordini di grandezza più grandi di qualsiasi cosa io conosca realisticamente il programma.

Sono semplicemente troppo ossessivo per lasciar andare l' osso "ma potrebbe far crescere quel grosso" osso, anche quando altre decisioni di progettazione lo impediscono di realisticamente accadere.

Tuttavia, a mia difesa, l'irrealistico dovrebbe diventare realtà ... l'ottimizzazione in realtà non è più "micro". Nota, non ho detto impossibile , ma irrealistico .

Naturalmente, i requisiti hanno la precedenza.


1
Ho lavorato per un'azienda che affondò per questo.
Henry,

2
@Henry - lo prometto, non sono stato io :)
Tim Post

1
@Henry: Vuoi dire che hanno perso tempo a ottimizzare le cose che probabilmente non sarebbero mai accadute, o non hanno pensato a cose che probabilmente "non" sarebbero mai accadute ... fino a quando non sono accadute ed era troppo tardi?
Dean Harding,

2
@Henry: se un'azienda ha un prodotto altamente scalabile e ancora affondato, è colpa delle vendite e del marketing (per non indirizzare i clienti ad alto volume e non valutare i prezzi in modo appropriato), non lo sviluppo.
rwong,

1
La società ha impiegato troppo tempo a progettare un sistema per milioni di utenti quando non avevano 1 utente. Deve essere stato un errore di marketing. Sì, diamo la colpa al marketing, quei ragazzi sono idioti.
Henry,

8

Penso di aver sprecato settimane a perdere tempo con i gestori di eccezioni Java.

Questo è molto lavoro per il codice che fallisce due o tre volte all'anno. Questo dovrebbe essere un avvertimento o un'informazione? Errore o fatale? È davvero fatale il processo verrà rigenerato tra cinque minuti? È davvero un avvertimento se tutto è ancora nello stato predefinito?

Un sacco di osservazione dell'ombelico e discussione sulla natura di un errore IO. Se non riesci a leggere un file in rete, si tratta di un errore di file o di un errore di rete? E così via.

Ad un certo punto ho sostituito tutte le stringhe di concat con String.formatcosì l'errore di file annuale non provoca oggetti extra nell'heap. Quello era uno spreco.


3
Questo è un lavoro importante. Il prezzo del fallimento = il tuo messaggio di errore è presente sul WTF giornaliero.
Steve314,

7

Suppongo che mi occupi troppo dei LOC. Non tanto LOC stessi, ma piuttosto numero di istruzioni e ancora più numero di istruzioni duplicate. Sono allergico al codice duplicato. In generale, adoro il refactoring, ma suppongo che circa il 50% di ciò che faccio non renda il codice significativamente più bello.


4
+1 per "Sono allergico al codice duplicato". Vedi anche la mia risposta qui: programmers.stackexchange.com/questions/14610/…
Macneil

Pensandoci - ho questo problema con i loop che si riferisce a un punto che Knuth ha fatto su goto, e talvolta devo scambiare un ciclo o due o un codice duplicato per scrivere codice strutturato. Io voglio usare un goto in casi molto rari (più comune = codice generato), ma la mia variante di questo disturbo è di sprecare tempo a preoccuparsi e giocherellare con un ciclo senza fine cercando di eliminare un'inefficienza banale ma mantenere il codice leggibile.
Steve314,

5

Leggere un file riga per riga anziché semplicemente leggere l'intera riga in una stringa ed elaborare la stringa in un unico take.

Certo, fa la differenza nella velocità di esecuzione ma raramente vale le righe extra di codice. Rende il codice molto meno gestibile e aumenta le dimensioni del codice.

Sì, questo probabilmente non ha senso se il file ha una dimensione di 3 GB, ma la maggior parte dei file non è così grande (almeno non quelli con cui sto lavorando ;-)).


3
Anche se è di 3 GB o più, un computer a 64 bit può gestirlo con memoria virtuale. Usa un file mappato in memoria e non leggerà nemmeno alcuna parte del tuo file finché non sarà necessario. Intendiamoci, anche questa è la micro-ottimizzazione nel caso normale.
Steve314,

3

Quando stavo scrivendo il linguaggio assembly, aveva senso puntare su byte e cicli, ma è stato tanto tempo fa e da allora i compilatori hanno fatto molta strada. Non proverei a ottimizzare manualmente uno adesso.

Allo stesso modo, quando sono passato a scrivere in C era abbastanza facile fare un lavoro migliore dei compilatori in C, ma ogni anno Borland o Microsoft o qualcuno ne rilasciava uno nuovo e migliorato che prendeva a calci il precedente nella stanza. Ho iniziato a prestare attenzione all'effettivo codice assembly che il compilatore stava emettendo e, pericoloso se non stava scrivendo un codice carino e stretto, srotolando loop, spostando variabili all'esterno dei loop, ecc.

Adesso sto scrivendo in lingue molto più alte come Perl, Python e Ruby. Uso alcuni trucchi del compilatore in anticipo, come lo srotolamento dei loop se ha senso, spostando le variabili statiche fuori dai loop, ecc., Ma non mi preoccupo quasi perché le CPU sono un po 'più veloci ora. Se un'app sembra trascinarsi inaspettatamente, userò un profiler e vedrò cosa riesco a trovare, quindi se qualcosa può essere migliorato inizierò a confrontare vari modi in cui riesco a pensare di fare qualcosa più velocemente, quindi vedo come si ingrandisce.

In generale, cerco di essere intelligente su come scrivo il codice, sulla base di anni di esperienza.


Ciao Greg, grazie per la risposta, ma sto cercando cosa fanno i programmatori per perdere tempo, non per ottimizzare le prestazioni di runtime. Ci sono due grandi esempi sopra: nomi di variabili e rimozione anche di duplicazioni minori di codice.
Macneil,

3

Una micro-ottimizzazione: migliorare le prestazioni a thread singolo di cose che sono parallelizzabili o che possono essere semplicemente migliorate con il nuovo hardware.

Se qualcosa è lento su un computer di 10 anni fa, una soluzione più economica è probabilmente quella di acquistare un computer più nuovo e più veloce, piuttosto che perdere tempo a ottimizzare il programmatore. Un grande focus sulle ottimizzazioni considerate, tuttavia, dovrebbe essere trovare un modo per usare gli 8 core che puoi ottenere oggi, o i 64 che sarai in grado di ottenere in un paio di anni, invece di angosciarti sulla minutia come il costo extra della spazzatura collezione.


2

La micro-ottimizzazione in termini di prestazioni di runtime non è quasi mai un problema chiuso anche oggi (anche se potrebbe essere meno comune). Occasionalmente devo spiegare alle persone che il sovraccarico di allocare un oggetto in più ogni richiesta o aggiungere una chiamata di funzione extra è trascurabile.

A parte questo, vedo anche i programmatori microottimizzare per semplicità (incluso me stesso). Devo ancora lavorare da qualche parte che non ho dovuto spiegare la differenza tra semplicità e semplicità.


Perché programmatori. essere diverso? Qual è la differenza, per favore.
Dan Rosenstark,

@Yar - Perché i programmatori dovrebbero essere diversi da cosa?
Jason Baker,

perché programmers.= programmers.stackexchange.comsarebbe diverso da ogni luogo in cui hai lavorato dove hai dovuto spiegare la differenza tra questi due concetti? Per favore, spiega la differenza.
Dan Rosenstark,

@Yar - Non lo so. In effetti, poiché il punto di programmers.se è aiutare i programmatori a mettere in comune le conoscenze, spero che non sia così che le persone possano essere almeno un po 'illuminate dalla mia risposta.
Jason Baker,

2
Quindi qual è la differenza tra semplicità e semplicità?
Dan Rosenstark,

2

Sono tutto per il principio non ottimizzare, a meno che non sia davvero necessario. E sono tutto per il principio primo profilo. E in linea di principio, ottimizzerò solo qualcosa che farà la differenza necessaria.

Questo è in linea di principio. Ma il principio è un bugiardo.

Ho l'abitudine di occuparmi delle funzioni nelle biblioteche usate di frequente che penso saranno usate molto nei circuiti interni. E poi, quando si individua qualcosa in un'altra funzione, non viene usato così spesso ...

Oh - e poi c'è la logica "Sto scrivendo - ovviamente è una libreria importante".

Oh - e BTW. Non ho mai usato un profiler per guidare un'ottimizzazione. Non ho accesso a uno commerciale e non ho mai sviluppato la motivazione per capire gprof.

Fondamentalmente, sono un ipocrita. Questi principi si applicano ad altre persone, ma ho troppa paura che qualcuno dica "ma perché l'hai scritto in quel modo lento e schifoso?" quindi non potrò mai applicarli correttamente a me stesso.

Non sono poi così male come faccio qui. E sono completamente immune all'autoinganno, quindi sai che ho ragione!

MODIFICARE

Dovrei aggiungere - uno dei miei maggiori stupidi agganci è il sovraccarico di chiamate. Non dappertutto, ovviamente, ma in quei casi in cui penso che sarà usato molto nei cicli interni (dove non ho prove oggettive di un problema). Ho scritto un brutto codice basato su offsetof per evitare di effettuare chiamate a metodi virtuali più di una volta. Il risultato potrebbe anche essere più lento, poiché probabilmente non è uno stile di codifica che gli ottimizzatori sono progettati per gestire bene - ma è più intelligente ;-)


+1 Ah, sì! Questa classe analizza gli argomenti della riga di comando altamente specifici e bizzarri della mia applicazione, ma lasciami formattare e documentarlo completamente quando Javadoc, perché sicuramente altri lo useranno per anni! [Dovrà votare più tardi, il mio limite giornaliero è raggiunto.]
Macneil,

@Macneil - quello è Doxygen, lo farò sapere. Con ogni opzione che riesco a trovare attivata, così ogni piccola funzione viene "documentata" con dettagli lancinanti, completa di una dozzina di grafici GraphViz. Aiuta davvero tutti ad apprezzare quanto sia importante il mio codice - e la stampa può tappezzare un blocco ufficio piuttosto grande.
Steve314,

1

Ai vecchi tempi in cui i computer avevano i tempi misurati in microsecondi, la memoria misurata in kilobyte e i compilatori primitivi, la micro-ottimizzazione aveva un senso.

La velocità e le dimensioni dei computer della generazione attuale e la qualità dei compilatori della generazione attuale significano che la micro-ottimizzazione è generalmente una perdita di tempo totale. Le eccezioni tendono ad essere quando devi assolutamente ottenere le massime prestazioni da un codice ad alta intensità computazionale ... o stai scrivendo per un sistema incorporato con risorse estremamente limitate.

ma sto cercando cosa fanno i programmatori per perdere tempo, non per ottimizzare le prestazioni di runtime.

Twitter e Facebook vengono in mente :-)


Ciao Stephen, questo è un grande commento sulla micro-ottimizzazione, ma vedi qualche equivalente moderno? [Facebook e Twitter non sono "buone pratiche" che possono essere portate troppo lontano.]
Macneil,

Ha ancora senso. I tempi dell'orologio potrebbero essere ordini di grandezza più piccoli, ma il codice è ordini di grandezza più grandi ...
hplbsh,

@Stuart - ciò significa che ci sono ordini di grandezza in più di codice da micro-ottimizzare ... che semplicemente non si ridimensiona.
Stephen C,
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.