while (condition) {
...
}
Flux de travail :
- vérifier l'état ;
- si faux, saut à l'extérieur de la boucle ;
- exécuter une itération ;
- sauter au sommet.
if (condition) do {
...
} while (condition);
Flux de travail :
- vérifier l'état ;
- si faux, saut au-delà de la boucle ;
- exécuter une itération ;
- vérifier l'état ;
- si c'est vrai, passez à l'étape 3.
En comparant les deux, vous pouvez facilement voir que la seconde peut ne pas faire de saut du tout, à condition qu'il y ait exactement une étape dans la boucle, et généralement le nombre de sauts sera inférieur d'une unité au nombre d'itérations. La première devra sauter en arrière pour vérifier la condition, pour ensuite sauter hors de la boucle lorsque la condition est fausse.
Les sauts sur les architectures modernes de CPU en pipeline peuvent être assez coûteux : alors que le CPU termine l'exécution des contrôles avant le saut, les instructions au-delà de ce saut sont déjà au milieu du pipeline. Tout ce traitement doit être abandonné si la prédiction de branchement échoue. L'exécution ultérieure est retardée pendant que le pipeline est réamorcé.
Explication de ce qui est mentionné prédiction de branche : pour chaque type de saut conditionnel, le CPU a deux instructions, chacune comprenant un Pariez sur sur le résultat. Par exemple, vous pouvez mettre une instruction disant " sauter si non zéro, parier sur non zéro "à la fin d'une boucle car le saut devra être effectué sur toutes les itérations sauf la dernière. De cette façon, le CPU commence à pomper son pipeline avec les instructions qui suivent la cible du saut au lieu de celles qui suivent l'instruction de saut elle-même.
Remarque importante
Faites-le, s'il vous plaît. no Prenez cela comme un exemple de la façon d'optimiser au niveau du code source. Ce serait une erreur puisque, comme le montre clairement votre question, la transformation de la première forme en la seconde est une opération de routine que le compilateur JIT effectue de manière totalement autonome.