2009-08-18 16 views
7

Mi stavo chiedendo, come ottimizzare i loop per sistemi con risorse molto limitate. Diciamo che, se abbiamo una base for ciclo, come (scritto in javascript):operazioni di base tempo di cpu costo


for(var i = someArr.length - 1; i > -1; i--) { someArr[i] }


Sinceramente non lo so, non è più conveniente che !=>?

sarei grato per tutte le risorse che coprono costo di calcolo in un contesto di operatori di base, come il suddetto, >>, ~, !, e così via.

+9

Aspetta, si sta cercando di micro-ottimizzare * * Javascript ?? –

+6

colloquialmente conosciuto come "download chrome" – skaffman

+4

risposta breve: supponiamo che ogni operazione richieda lo stesso tempo. Non è * sempre * vero, ma è un'approssimazione decente. – jalf

risposta

15

Le prestazioni su una CPU moderna sono tutt'altro che banali. Ecco un paio di cose che lo complicano:

  • I computer sono veloci. La tua CPU può eseguire fino a 6 miliardi di istruzioni al secondo. Quindi, anche l'istruzione più lento può essere eseguita milioni di volte al secondo, il che significa che è veramente solo conta se lo si utilizza molto spesso
  • centinaia moderna sono CPU di istruzioni in volo contemporaneamente. Sono pipeline, il che significa che mentre un'istruzione viene letta, un'altra sta leggendo da registri, una terza è in esecuzione e una quarta sta scrivendo di nuovo su un registro. Le CPU moderne hanno 15-20 di tali fasi. Inoltre, possono eseguire 3-4 istruzioni contemporaneamente su ciascuna di queste fasi. E possono riordinare queste istruzioni. Se l'unità di moltiplicazione viene utilizzata da un'altra istruzione, possiamo trovare, ad esempio, un'istruzione di addizione da eseguire.Quindi, anche se hai un po 'di istruzioni lente mescolate, il loro costo può essere nascosto molto bene il più delle volte, eseguendo altre istruzioni mentre aspetti che quello lento finisca.
  • La memoria è centinaia di volte più lenta della CPU. Le istruzioni che vengono eseguite non hanno molta importanza se il loro costo è sminuito dal recupero dei dati dalla memoria. E anche questo non è affidabile, perché la CPU ha le proprie cache di bordo per tentare di nascondere questo costo.

Quindi la risposta breve è "non cercare di superare in astuzia il compilatore". Se sei in grado di scegliere tra due espressioni equivalenti, il compilatore è probabilmente in grado di fare lo stesso, e sceglierà quello più efficiente. Il costo di un'istruzione varia in base a tutti i fattori sopra indicati. Quali altre istruzioni sono in esecuzione, quali dati sono nella cache della CPU, quale preciso modello di CPU è il codice in esecuzione e così via. Il codice super efficiente in un caso può essere molto inefficiente in altri casi. Il compilatore proverà a scegliere le istruzioni più efficienti e programmarle nel miglior modo possibile. A meno che tu non sappia più del compilatore su questo, è improbabile che tu possa fare un lavoro migliore.

Non provare tali microottimizzazioni a meno che tu non sia davvero sapere cosa stai facendo. Come mostrato in precedenza, le prestazioni a basso livello sono un argomento ridicolmente complesso ed è molto facile scrivere "ottimizzazioni" che portano a un numero di inferiore più lento. O che semplicemente sacrificano la leggibilità su qualcosa che non fa alcuna differenza.

Inoltre, la maggior parte del codice semplicemente non ha un impatto misurabile sulle prestazioni. persone generalmente ama citando (o misquoting) Knuth su questo argomento:

Dobbiamo dimenticare le piccole efficienze, dicono circa il 97% del tempo: l'ottimizzazione prematura è la radice di tutti i mali

persone spesso lo interpretano come "non preoccuparti di cercare di ottimizzare il tuo codice". Se leggi effettivamente la citazione completa, alcune conseguenze molto più interessanti dovrebbero essere chiare:

Per la maggior parte del tempo, dovremmo dimenticare le microottimizzazioni. La maggior parte del codice viene eseguita così raramente che le ottimizzazioni non contano. Tenendo presente il numero di istruzioni che una CPU può eseguire al secondo, è ovvio che un blocco di codice deve essere eseguito molto spesso perché le ottimizzazioni abbiano effetto. Quindi, circa il 97% delle volte, le tue ottimizzazioni saranno una perdita di tempo. Ma dice anche che a volte (il 3% delle volte), le tue ottimizzazioni corrisponderanno a. E ovviamente, cercare quei 3% è un po 'come cercare un ago in un pagliaio. Se decidi di "ottimizzare il tuo codice" in generale, perdi tempo con il primo 97%. Invece, è necessario innanzitutto individuare il 3% che effettivamente ha bisogno di essere ottimizzato. In altre parole, esegui il tuo codice attraverso un profiler e lascia che ti indichi quale codice occupa più tempo della CPU. Allora sai dove ottimizzare. E poi le tue ottimizzazioni non sono più premature.

+0

Risposta superlativa. Se fossi l'OP, accetterei questa risposta. –

+0

Grazie, questo praticamente lo riassume, considerando l'approccio. Dovrò profilare il mio codice contro alcuni array reali e solo vedere. Le moderne CPU sono veloci, ma le CPU nei sistemi embedded sono lontane da quello. Quindi la mia domanda. Cheers! – Kosmotaur

+1

Aspetta un secondo. Stai usando javascript su un sistema embedded e sei preoccupato per le prestazioni? – jalf

1

La maggior parte dei confronti ha la stessa costa, perché il processore la confronta semplicemente in tutti gli aspetti, quindi dopo prende una decisione basata su flag generati da questo confronto precedente, quindi il segnale di confronto non ha alcuna importanza. Ma alcune architetture cercano di accelerare questo processo in base al valore con cui si sta confrontando, come il confronto con 0.

Per quanto ne so, le operazioni bit a bit sono le operazioni più economiche, leggermente più veloci di addizioni e sottrazioni. Le operazioni di moltiplicazione e divisione sono un po 'più costose e il confronto è l'operazione costiera più elevata.

9

È straordinariamente improbabile che tali micro-ottimizzazioni apportino una differenza notevole al codice in qualsiasi, tranne le circostanze più estreme (i sistemi embedded in tempo reale?). Il tuo tempo sarebbe probabilmente servito meglio a preoccuparti di rendere il tuo codice leggibile e mantenibile.

In caso di dubbio, inizia sempre chiedendo Donald Knuth:

http://shreevatsa.wordpress.com/2008/05/16/premature-optimization-is-the-root-of-all-evil/

Oppure, per un po 'meno alta della fronte assumere micro-ottimizzazione:

http://www.codinghorror.com/blog/archives/000185.html

+1

Manca il punto della citazione di Knuth. Knuth ha detto solo che era una cattiva idea circa il 97% delle volte, il che implica che è significativo e utile il 3% delle volte. Non è "straordinariamente improbabile" che la microottimizzazione possa fare la differenza. Succede tutto il tempo. Significa solo che, a meno che tu non sappia * cosa * ottimizzare, è probabile che tu raggiunga il 97% dove non raggiunge una differenza evidente. – jalf

+0

Punto eccellente. A mia difesa, ho detto "tali micro-ottimizzazioni" piuttosto che "tutte le micro-ottimizzazioni" poiché il poster originale era preoccupato della differenza tra! = E> in un ciclo javascript for. –

+0

Perché ottimizzare Javascript? http://www.6502asm.com/ <= Questo è un emulatore e un assembler 6502 nell'app JavaScript! Davvero bello e ovviamente il risultato di una mente malata con troppo tempo a disposizione, ma comunque VERAMENTE interessante. (Un sacco di cose divertenti sono il risultato di un malato, quindi non esagerare.) – NoMoreZealots

0

ottimizzazione prematura può essere pericoloso l'approccio migliore sarebbe quello di scrivere la tua applicazione senza preoccuparsi di ciò e quindi trovare i punti lenti e ottimizzare quelli. Se sei veramente preoccupato, usa un linguaggio di livello inferiore. Un linguaggio interpretato come javascript ti costerà un po 'di potenza di elaborazione se confrontato con un linguaggio di livello inferiore come C.

0

In questo caso particolare,> vs = non è probabilmente un problema di perfomance. TUTTAVIA> è generalmente una scelta più sicura perché impedisce i casi in cui il codice è stato modificato per essere scaricato nelle erbacce e bloccato in un ciclo infinito.

1

È come chiedere un pesce, quando preferirei insegnarti a pescare.

Ci sono modi semplici per vedere da solo quanto tempo ci vuole. Il mio preferito è copiare il codice 10 volte e poi avvolgerlo in un ciclo di 10^8 volte.Se lo eseguo e guardo il mio orologio, il numero di secondi che impiega si traduce in nanosecondi.

Dire di non fare l'ottimizzazione prematura è un "non essere". Se vuoi un "fai essere" puoi provare una tecnica di ottimizzazione delle prestazioni proattiva come this.

BTW il mio modo preferito di codificare il ciclo è:

for (i = N; --i >= 0;){...} 
Problemi correlati