29 votes

Efficacité : les instructions switch par rapport aux instructions if

PMD me dit

Un switch avec moins de 3 branches est inefficace, utilisez une instruction if. à la place.

Pourquoi ? Pourquoi 3 ? Comment définissent-ils l'efficacité ?

38voto

Jack Points 61503

Parce qu'un switch est compilé avec deux instructions spéciales de la JVM qui sont lookupswitch y tableswitch . Ils sont utiles lorsque l'on travaille avec un grand nombre de cas, mais ils entraînent une surcharge lorsque l'on n'a que quelques branches.

Un site if/else au lieu d'être compilé dans une déclaration typique je jne ... chaînes qui sont plus rapides mais nécessitent beaucoup plus de comparaisons lorsqu'elles sont utilisées dans une longue chaîne de branches.

Vous pouvez voir la différence en regardant le code d'octet, dans tous les cas, je ne m'inquiéterais pas de ces questions, si quelque chose peut devenir un problème, le JIT s'en occupera.

Exemple pratique :

switch (i)
{
  case 1: return "Foo";
  case 2: return "Baz";
  case 3: return "Bar";
  default: return null;
}

est compilé en :

L0
 LINENUMBER 21 L0
 ILOAD 1
 TABLESWITCH
   1: L1
   2: L2
   3: L3
   default: L4
L1
 LINENUMBER 23 L1
FRAME SAME
 LDC "Foo"
 ARETURN
L2
 LINENUMBER 24 L2
FRAME SAME
 LDC "Baz"
 ARETURN
L3
 LINENUMBER 25 L3
FRAME SAME
 LDC "Bar"
 ARETURN
L4
 LINENUMBER 26 L4
FRAME SAME
 ACONST_NULL
 ARETURN

Alors que

if (i == 1)
  return "Foo";
else if (i == 2)
  return "Baz";
else if (i == 3)
  return "Bar";
else
  return null;

est compilé en

L0
 LINENUMBER 21 L0
 ILOAD 1
 ICONST_1
 IF_ICMPNE L1
L2
 LINENUMBER 22 L2
 LDC "Foo"
 ARETURN
L1
 LINENUMBER 23 L1
FRAME SAME
 ILOAD 1
 ICONST_2
 IF_ICMPNE L3
L4
 LINENUMBER 24 L4
 LDC "Baz"
 ARETURN
L3
 LINENUMBER 25 L3
FRAME SAME
 ILOAD 1
 ICONST_3
 IF_ICMPNE L5
L6
 LINENUMBER 26 L6
 LDC "Bar"
 ARETURN
L5
 LINENUMBER 28 L5
FRAME SAME
 ACONST_NULL
 ARETURN

7voto

Tim Pote Points 8905

Bien que l'utilisation d'un commutateur présente des gains d'efficacité mineurs par rapport à l'utilisation d'une déclaration if, ces gains sont négligeables dans la plupart des cas. Et tout analyseur de code source digne de ce nom reconnaîtrait que micro-optimisations sont secondaires à la clarté du code.

Ils disent qu'une instruction if est à la fois plus simple à lire et occupe moins de lignes de code qu'une instruction switch si le switch est sensiblement court.

De la Site web de la PMD :

Trop peu de branches pour une déclaration de commutation : Les instructions de commutation sont censées être utilisées pour supporter un comportement de branchement complexe. Il n'est pas conseillé d'utiliser un commutateur pour quelques cas seulement, car les commutateurs ne sont pas aussi faciles à comprendre que les instructions if-then. Dans ces cas, utilisez l'instructionif-then pour améliorer la lisibilité du code.

6voto

Stephen C Points 255558

Pourquoi ça ?

Différentes séquences d'instructions sont utilisées lorsque le code est (enfin) compilé en code natif par le compilateur JIT. Un commutateur est implémenté par une séquence d'instructions natives qui effectuent un branchement indirect. (La séquence charge généralement une adresse à partir d'une table, puis effectue un branchement à cette adresse). Un if / else est implémenté comme des instructions qui évaluent la condition (probablement une instruction de comparaison) suivie d'une instruction de branchement conditionnel.

Pourquoi 3 ?

C'est une observation empirique, je suppose qu'elle est basée sur l'analyse des instructions du code natif généré et/ou sur l'évaluation comparative. (Ou peut-être pas. Pour en être absolument sûr, il faudrait demander à l'auteur ou aux auteurs de cette règle PMD comment ils ont obtenu ce chiffre).

Comment définissent-ils l'efficacité ?

Temps nécessaire à l'exécution des instructions.


Personnellement, je ne suis pas d'accord avec cette règle... ou plus précisément avec le message. Je pense qu'elle devrait dire qu'un if / else est plus simple et plus lisible qu'un switch avec 2 cas. La question de l'efficacité est secondaire, et probablement non pertinente.

1voto

thebarcodeproject Points 530

Je crois qu'il a à faire avec la manière d'un interrupteur, et un if/else compile vers le bas.

Dit qu'il faut 5 calculs pour le traitement d'une instruction switch. Dire une instruction if prend les deux calculs. Moins de 3 options de votre commutateur serait égal à 4 calculs en ifs vs 5 dans les commutateurs. Toutefois, la charge reste constante dans un switch, donc si il a 3 choix, ifs, serait de 3 * 2 traitées, contre 5 encore pour le commutateur.

Les gains réalisés lors de la recherche à des millions de calculs sont extrêmement négligeable. Son plus une question de "c'est la meilleure façon de le faire", plutôt que de tout ce qui pourrait vous affecter. Il ne serait que de le faire sur quelque chose que les cycles sur la fonction des millions de fois dans une itération.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X