Je peux reproduire ce phénomène sur mon Q6600 (Python 2.6.2) en augmentant la plage à 100000000 :
('+=', 11.370000000000001)
('-=', 10.769999999999998)
Tout d'abord, quelques observations :
- Cela représente 5 % pour une opération triviale. C'est significatif.
- La vitesse des opcodes natifs d'addition et de soustraction n'est pas pertinente. Elle est dans le bruit de fond, complètement éclipsée par l'évaluation du bytecode. Il s'agit d'une ou deux instructions natives sur des milliers.
- Le bytecode génère exactement le même nombre d'instructions ; la seule différence est la suivante
INPLACE_ADD
vs. INPLACE_SUBTRACT
et +1 contre -1.
En regardant la source Python, je peux faire une supposition. Ceci est géré dans ceval.c, dans PyEval_EvalFrameEx
. INPLACE_ADD
a un bloc de code supplémentaire significatif, pour gérer la concaténation des chaînes de caractères. Ce bloc n'existe pas dans INPLACE_SUBTRACT
puisque vous ne pouvez pas soustraire des chaînes de caractères. Cela signifie que INPLACE_ADD
contient plus de code natif. Selon la façon dont le code est généré par le compilateur, ce code supplémentaire peut être en ligne avec le reste du code INPLACE_ADD, ce qui signifie que les additions peuvent toucher le cache d'instructions plus durement que les soustractions. Ce site pourrait provoquer des accès supplémentaires au cache L2, ce qui pourrait entraîner une différence de performances significative.
Cela dépend fortement du système utilisé (les différents processeurs ont des quantités de cache et des architectures de cache différentes), du compilateur utilisé, y compris la version particulière et les options de compilation (différents compilateurs décideront différemment quels bits de code sont sur le chemin critique, ce qui détermine comment le code d'assemblage est regroupé), etc.
En outre, la différence est inversée dans Python 3.0.1 (+ : 15.66, - : 16.71) ; il ne fait aucun doute que cette fonction critique a beaucoup changé.