Question

boolean a = false, b = true;
if ( a && b ) { ... };

Dans la plupart des langues, b ne sera pas évalué car a est false, donc a & amp; & amp; b ne peut pas être vrai. Ma question est la suivante: le court-circuit ne serait-il pas plus lent en termes d'architecture? Dans un pipeline, bloquez-vous en attendant le résultat de a pour déterminer si b doit être évalué ou non? Serait-il préférable de faire des if imbriqués à la place? Est-ce que ça aide même?

De plus, est-ce que quelqu'un sait quelle évaluation de court-circuit est généralement appelée? Cette question a été soulevée après avoir découvert que mon ami programmeur n'avait jamais entendu parler de l'évaluation de court-circuit et avait déclaré qu'elle n'était pas courante, ni trouvée dans de nombreuses langues, et qu'elle était inefficace dans les processus en cours. Je ne suis pas certain de la dernière question, alors je vous le demande!

D'accord, je pense à un exemple différent pour peut-être expliquer la provenance de mon ami. Il estime que depuis l’évaluation parallèle d’une déclaration semblable à celle-ci:

(a) if ( ( a != null ) && ( a.equals(b) ) ) { ... }

plantera le système en panne, une architecture sans court-circuit (et donc ne permettant pas les déclarations comme ci-dessus) serait plus rapide dans le traitement des instructions comme celles-ci:

(b) if ( ( a == 4 ) && ( b == 5 ) )

puisque s'il ne peut pas faire (a) en parallèle, il ne peut pas faire (b) en parallèle. Dans ce cas, un langage qui permet de court-circuiter est plus lent que celui qui ne le fait pas.

Je ne sais pas si c'est vrai ou non.

Merci

Était-ce utile?

La solution

Les expressions booléennes en court-circuit sont exactement équivalentes à un ensemble de if imbriqués, elles sont donc aussi efficaces qu'elles le seraient.

Si b n'a pas d'effets secondaires, il peut toujours être exécuté en parallèle avec a (pour toute valeur de "en parallèle", pipelining compris).

Si b a des effets secondaires que l’architecture de la CPU ne peut pas annuler en cas d’échec de la prédiction de branche, il est possible qu’un retard soit inévitable si les deux côtés étaient toujours évalués. C’est donc quelque chose à regarder si jamais vous trouvez que les opérateurs de court-circuit créent un goulot d’étranglement dans les performances de votre code, mais ne vous inquiétez pas autrement.

Mais le court-circuit est utilisé autant pour le contrôle du flux que pour l’économie de travail inutile. C'est courant parmi les langues que j'ai utilisées, par exemple l'idiome Perl:

open($filename) or die("couldn't open file");

l'idiome du shell:

do_something || echo "that failed"

ou l'idiome C / C ++ / Java / etc:

if ((obj != 0) && (obj->ready)) { do_something; } // not -> in Java of course.

Dans tous ces cas, vous avez besoin d'un court-circuit afin que le RHS ne soit évalué que si le LHS le dicte. Dans de tels cas, il est inutile de comparer les performances avec du code alternatif qui ne va pas!

Autres conseils

L’évaluation des circuits courts est traduite en branches en langage assembleur de la même manière si les instructions sont (les branches sont essentiellement un goto), ce qui signifie qu’elles ne seront pas plus lentes que si les instructions if.

Les branches ne bloquent généralement pas le pipeline, mais le processeur devinera si la branche est prise ou non, et si le processeur est erroné, il devra effacer tout ce qui s’est passé depuis qu’il a mal deviné.

L’évaluation du court-circuit est également son nom le plus courant. On la trouve dans la plupart des langues sous une forme ou une autre.

Honnêtement, je ne m'inquiéterais pas pour ça. Tester un booléen est très rapide . Les courts-circuits ne deviennent intéressants / utiles que lorsque la deuxième expression a des effets secondaires:

if ( ConfirmAction() && DestroyAllData() )
   Reboot();

... ou dépend du premier test:

if ( myDodgyVar != null && myDodgyVar.IsActive() )
   DoSomethingWith(myDodgyVar);

Langues prenant en charge le court-circuit:

Ada, Eiffel, ALGOL 68, C1, C ++, C #, Java, R, Erlang, ML standard, Javascript, MATLAB, Lisp, Lua, Schéma, OCaml, Haskell, Pascal, Perl, Ruby, PHP, Python, Smalltalk , Visual Basic .NET

Extrait de Évaluation des courts-circuits

VB.Net a une syntaxe différente selon que vous voulez ou non court-circuiter. Pour des raisons héritées du passé, le comportement par défaut est de ne pas court-circuiter. La syntaxe est la suivante

Pas de court-circuit

IF A And B THEN
    ...
END IF

Court-circuit

IF A AndAlso B THEN
    ...
END IF

Vous pouvez utiliser Or / OrElse si vous souhaitez court-circuiter une instruction OR. Ce qui est vraiment bien dans des situations comme celle-ci

If MyObj IsNot Nothing AndAlso MyObj.Value < SomeValue Then
    ....
End If

Personnellement, même si j’ai bien compris que le court-circuit peut accélérer les choses, ce n’est certainement pas une évidence de regarder le code. Je pouvais voir un développeur inexpérimenté se confondre avec le comportement. Cela semble même quelque chose qui pourrait arriver ou non en fonction des indicateurs du compilateur pour le niveau d'optimisation. J'aime la façon dont VB parle de quel comportement vous voulez réellement accomplir.

D'abord, votre ami a tort. L’évaluation des courts-circuits (aussi appelée évaluation minimale) est disponible dans la plupart des langues et vaut mieux que des if imbriquées pour les langues parallèles (auquel cas la première des conditions renvoyées entraîne la poursuite de l’exécution)

Dans tous les cas, même dans un langage simple et non parallèle, je ne vois pas comment les imbriqués seraient plus rapides, car l'exécution serait bloquée jusqu'à ce que la première condition soit évaluée.

Comment un imbriqué peut-il ne pas décrocher? En fait, si a et b sont à la fois des variables et pas des expressions ayant des effets secondaires, ils peuvent être chargés en parallèle par un bon compilateur. Il n'y a aucun avantage à utiliser plus de if si ce n'est d'augmenter le nombre de lignes. Vraiment, ce serait la pire sorte de seconde à deviner un compilateur.

Cela s'appelle l'évaluation de court-circuit.

Un court-circuit utile que j'utilise ressemble à ceci:

if (a != null && a.equals(somevalue)) {
    ... do something.
}

Ceci est, à mon avis, très lisible et fonctionne très bien. En général, j'essaie aussi d'éviter de trop imbriquer car cela conduit à un code laid.

Tout mon avis cependant.

La plupart des langues évaluent en court-circuit les expressions booléennes. J'ai toujours entendu parler de l'évaluation de court-circuit.

L'exemple de la question est un exemple assez simpliste qui n'apporte pas vraiment d'avantages en termes de performances. L'avantage en termes de performances survient lorsque les expressions sont complexes à évaluer.

Par exemple, imaginez un programme de jeu présentant les caractéristiques suivantes:

if (someObject.isActive() && someOtherObject.isActive() && CollisionDetection.collides(someObject, someOtherObject) {
  doSomething();
}

Dans ce cas, la détection de collision coûte beaucoup plus cher que les contrôles actifs. Il y aurait une amélioration significative des performances s'il y avait beaucoup d'objets inactifs dans le système.

Un court-circuit ou une évaluation minimale est simplement un sucre syntaxique pour les if imbriqués. Supposer que cela est inefficace ou provoque des blocages est un cas d'optimisation prématurée. À ce stade, la plupart des compilateurs sont suffisamment intelligents pour interpréter et optimiser correctement ces déclarations. L'utilisation de ces instructions peut considérablement réduire l'imbrication, et donc améliorer la lisibilité du code, ce qui devrait être votre objectif numéro un.

En ce qui concerne l'efficacité du court-circuit ou non, il est peu probable que le traitement en pipeline influe beaucoup sur les performances. Dans les situations où cela pourrait avoir un impact, rien n'empêche le compilateur de tester plusieurs conditions en parallèle tant que ces tests n'ont pas d'effets secondaires. De plus, les processeurs modernes disposent de plusieurs mécanismes utiles pour améliorer les performances du code de branche dans le pipeline.

Les ifs imbriqués auront le même effet que les courts-circuits & amp; & amp;.

"Évaluation de court-circuit" est le nom le plus courant, et votre ami a tort de dire que c'est inhabituel; c'est très courant.

Je ne connais rien au traitement en pipeline, mais l’évaluation des courts-circuits est une caractéristique commune à de nombreuses langues (et c’est aussi le nom par lequel je le connais). En C, & amp; & amp; et les autres opérateurs définissent un point de séquence comme le; l’opérateur le fait, alors je ne vois pas en quoi l’évaluation des courts-circuits est moins efficace que la simple utilisation de déclarations multiples.

Je n’en ai entendu parler que d’un court-circuit. dans un pipeline, la prochaine opération à exécuter ne dépend-elle pas du résultat de la déclaration if? si tel est le cas, cela serait plus optimisé et il ne serait pas nécessaire de tester deux valeurs à chaque fois.

Un seul thread est séquentiel, donc si vous avez deux ifs, le premier sera bien sûr évalué avant le second, donc je ne vois pas de différence à ce sujet. J'utilise l'opérateur conditionnel-AND (qui s'appelle comme ça) bien plus que des if imbriqués. Si je veux vérifier quelque chose qui peut prendre un certain temps à évaluer, je fais le test le plus simple en premier, puis le plus difficile après le conditionnel et.

a = obj.somethingQuickToTest() && obj.somethingSlowToTest();

ne semble pas être différent de

a = false;
if(obj.somethingQuickToTest())
   a = obj.somethingSlowToTest();

En fonction du contexte, vous pouvez également l'appeler "Garde".

Et je l'ai vu dans presque toutes les langues dans lesquelles j'ai travaillé - ce qui en fait près d'une douzaine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top