2017-07-22 6 views
4

Dies ist eine Optimierungsfrage. Ich habe einen Ausdruck in einer Funktion wie folgt aus:Wie funktioniert diese interne Python-Optimierung für mathematische Ausdrücke?

>>> def x(): 
...  num = 2 * 4 * 100 * 20 
... 
>>> x.__code__.co_consts 
(None, 2, 4, 100, 20, 8, 800, 16000) 

Das Ergebnis des Ausdrucks 2 * 4 * 100 * 20 ist 16000, so dass, wenn wir die x zerlegen:

>>> dis.dis(x) 
    2   0 LOAD_CONST    7 (16000) 
       3 STORE_FAST    0 (x) 
       6 LOAD_CONST    0 (None) 
       9 RETURN_VALUE  

Die 16000 ist ziemlich viel, was ist notwendig. co_consts Speicher 8 und 800, die technisch nicht mehr benötigt werden, haben wir die Summe oder sind sie?

den obigen Ausdruck mit einem anderen Vergleich:

>>> def x(): 
...  num = 3 + 4 + 9 * 4 
... 
>>> x.__code__.co_consts 
(None, 3, 4, 9, 7, 36) 

sieht aus wie der Bytecode-Compiler Binäroperanden nimmt und speichert deren Berechnung Werte:

9 * 4 36 
3 + 4 7 

Zerlegen der Funktion:

>>> dis.dis(x) 
    2   0 LOAD_CONST    4 (7) 
       3 LOAD_CONST    5 (36) 
       6 BINARY_ADD   
       7 STORE_FAST    0 (num) 
      10 LOAD_CONST    0 (None) 
      13 RETURN_VALUE 

Interessanterweise, wenn Sie diesen Ausdruck nehmen: 2 + 5 * 8 - 5 + 23 * 4, co_consts wird (None, 2, 5, 8, 23, 4, 40, 92) nur die Multiplikationen wurden berechnet: 5 * 8 und 23 * 4 die Addition und Subtraktion wurden ignoriert.

Wie funktioniert diese Optimierung wirklich? Ich habe das nur am 2.7 getestet.

+4

Sie sind Zeuge einige Gauner Optimierung Tricks. Überprüfen Sie ['peephole.c'] (https://github.com/python/cpython/blob/v3.6.1/Python/peephole.c). –

Antwort

4

Es gibt keine Erklärung dafür ;-) Bedeutet, dass es eine dunkle Ecke ist, die die Implementierungsdetails vollständig widerspiegelt. Der verantwortliche "Peephole-Optimierer" arbeitet besser oder schlechter nicht an einem Syntaxbaum des Programms, sondern am generierten Byte-Code. Das ist schwerfällig, daher ist es schwierig vorherzusagen, was passieren wird. Zum Beispiel, hier unter Python 3.6.1:

>>> def f(): 
...  return 2 + 5 * 8 - 5 + 23 * 4 
>>> f.__code__.co_consts 
(None, 2, 5, 8, 23, 4, 40, 42, 37, 92, 129) 
>>> import dis 
>>> dis.dis(f) 
    2   0 LOAD_CONST    10 (129) 
       2 RETURN_VALUE 

So wurde der Ausdruck auf ihren Endwert zusammengebrochen, aber alle Zwischenwerte wurden hinter in dem Tupel von Konstanten verlassen.

@COLDSPEED bereits mit dem Quellcode in ihrem Kommentar verknüpft, und die einzige echte Antwort auf eine Frage darüber muss von peephole.c in der Version von CPython, die Sie ausgeführt werden, starrte. Mit der Zeit wird es langsam ehrgeiziger, aber es gibt keinen wirklichen Plan dahinter.

Verwandte Themen