Einmal, nachdem ich Mike Mullers Tutorial zur Leistungsoptimierung gesehen hatte (ich denke dieses ), fing ein Gedanke an in meinem Kopf zu leben: Wenn Leistung wichtig ist, minimieren Sie den Zugriff auf Elemente in der Schleife nach Index, e. G. Wenn Sie in einer Schleife auf x[1]
mehrfach zugreifen müssen for x in l
- Weisen Sie x[1]
eine Variable zu und verwenden Sie sie in der Schleife erneut.
Jetzt habe ich dieses synthetische Beispiel:
%Vor% Die Funktionen unpacking()
und no_unpacking()
geben das gleiche Ergebnis zurück. Die Implementierung ist anders: unpacking()
entpackt die Elemente in a
und b
in der Schleife; no_unpacking()
ruft Werte nach Indizes ab.
Für python27 wird angezeigt:
%Vor% Mit anderen Worten, unpacking()
übertrifft no_unpacking()
um ~ 25%.
Die Frage ist:
Bonusfrage:
pypy
versucht - es gibt fast keinen Unterschied zwischen diesen beiden Funktionen, in Bezug auf die Leistung. Warum ist das so? Danke für jede Hilfe.
Um Ihre Fragen zu beantworten, können wir den von den beiden Funktionen erzeugten Bytecode mit dem Modul dis
überprüfen:
Ich habe das Listenverständnis erweitert, weil es in python3 mühsamer wäre, die interessanten Bytecodes zu überprüfen. Der Code ist äquivalent und spielt für unseren Zweck keine Rolle.
Der Bytecode für die erste Funktion lautet:
%Vor% Beachten Sie, dass die Schleife BINARY_SUBSCR
zweimal aufrufen muss, um auf die zwei Elemente des Tupels zuzugreifen.
Der Bytecode für die zweite Funktion lautet:
%Vor% Beachten Sie, dass BINARY_SUBSCR
nicht ausgeführt werden kann.
Es sieht so aus, als ob UNPACK_SEQUENCE
plus eins STORE_FAST
(das sind die zusätzlichen Operationen, die durch das Entpacken hinzugefügt werden) schneller sind als zwei BINARY_SUBSCR
.
Dies ist sinnvoll, da BINARY_SUBSCR
ein vollständiger Methodenaufruf ist, während UNPACK_SEQUENCE
und STORE_FAST
einfachere Operationen sind.
Sie können den Unterschied selbst in einfacheren Fällen sehen:
%Vor% Wie Sie sehen können, ist das Iterieren über eine Zeichenfolge mit expliziter Indizierung ungefähr dreimal langsamer.
Das ist alles Overhead aufgrund von Aufrufen von BINARY_SUBSCR
.
Zu Ihrer zweiten Frage: pypy hat JIT, das den Code analysieren kann und eine optimierte Version erzeugt, die den Overhead der Indexierungsoperationen vermeidet.
Wenn es erkennt, dass die Subskription auf Tupeln erfolgt, ist es wahrscheinlich möglich, Code zu erzeugen, der die Tupel-Methode nicht aufruft, sondern direkt auf die Elemente zugreift, wodurch die BINARY_SUBSCR
-Operationen vollständig entfernt werden.
Tags und Links python performance for-loop iterable-unpacking