while (condition) {
...
}
Flusso di lavoro:
- controllare le condizioni;
- se falso, salta fuori dal ciclo;
- eseguire un'iterazione;
- salta in cima.
if (condition) do {
...
} while (condition);
Flusso di lavoro:
- controllare le condizioni;
- se falso, salta oltre il ciclo;
- eseguire un'iterazione;
- controllare le condizioni;
- se è vero, vai al passaggio 3.
Confrontando questi due si può facilmente vedere che quest'ultimo potrebbe non fare alcun salto, a condizione che ci sia esattamente un passaggio attraverso il ciclo, e generalmente il numero di salti sarà uno in meno rispetto al numero di iterazioni. Il primo dovrà tornare indietro per controllare la condizione, solo per saltare fuori dal ciclo quando la condizione è falsa.
I salti sulle moderne architetture di CPU in pipeline possono essere piuttosto costosi: poiché la CPU sta terminando l'esecuzione dei controlli prima del salto, le istruzioni oltre quel salto sono già nel mezzo della pipeline. Tutta questa elaborazione deve essere scartata se la previsione del ramo fallisce. L'ulteriore esecuzione viene ritardata mentre la pipeline viene riattivata.
Spiegazione della previsione del ramo citato : per ogni tipo di salto condizionale la CPU ha due istruzioni, ciascuna inclusa una scommessa sul risultato. Ad esempio, potresti mettere un'istruzione che dice " salta se non zero, scommettendo su non zero " alla fine di un ciclo perché il salto dovrà essere fatto su tutte le iterazioni tranne l'ultima. In questo modo la CPU inizia a pompare la sua pipeline con le istruzioni che seguono l'obiettivo di salto invece di quelle che seguono l'istruzione di salto stessa.
Nota importante
Si prega di non prenderlo come esempio di come ottimizzare a livello di codice sorgente. Ciò sarebbe del tutto fuorviante poiché, come già chiaro dalla tua domanda, la trasformazione dalla prima forma alla seconda è qualcosa che il compilatore JIT fa come una questione di routine, completamente da solo.