2016-08-08 29 views
0

Ich versuche, die Geschwindigkeit Verbesserung der Verwendung von JIT in Python zu testen. Hier ist der Code, den ich verwende.Impossible Beschleunigungen bei Verwendung von JIT in Python. Was ist los?

from numba import jit 
import timeit 

@jit # Commented out when testing pure python 
def sumof(): 
    x = 0 
    for i in xrange(1000000000): 
     x += 1 
    return x 

def timer(): 
    sumof() # Run once to initialize the JIT compiler 
    l = [] 
    t = timeit.default_timer() 
    for x in range(10): 
     l.append(sumof()) 
    return timeit.default_timer()-t, l # Returns the time elapsed and the list of results, to verify accuracy 

print timer() 

Dies ergibt ein ähnliches Ergebnis wie dieses

(5.643910299113486e-06, [1000000000, 1000000000, 1000000000, 1000000000, 1000000000, 1000000000, 1000000000, 1000000000, 1000000000, 1000000000]) 

Jetzt weiß ich rohe CPU-Leistung um Größenordnungen schneller als reine Python, aber 10 Milliarden Operationen in 5 Mikrosekunden ?? Ich habe denselben Code getestet, aber den maximalen Wert einer 64-Bit-Ganzzahl mit Vorzeichen anstelle von nur einer Milliarde verwendet. Das war das Ergebnis.

(5.643909389618784e-06, [9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L, 9223372036854775807L]) 

~ 92 Billiarden Operationen ... in 5 Mikrosekunden. Nach meiner Mathematik sind das etwa 16 Septillionen pro Sekunde. Etwas ist offensichtlich falsch, aber es gibt das richtige Ergebnis. Ich vermute, dass der Compiler die for-Schleife irgendwie loswird, aber warum? Und wie kann ich das verhindern?

+0

'für i in xrange (1000000000): x + = 1 'ist eine sehr einfache Schleife (vereinfacht natürlich auf' 1000000000'), vielleicht optimiert der Maschinencode es komplett. – 101

+1

Umm, ist das nicht das Ergebnis Ihres Benchmarks? Zumindest in diesem Fall ist der Beschleunigungsfaktor bei Verwendung von Numba's jit wirklich 10^8. – phihag

+0

@ 101 Es passiert auch, wenn ich die Funktion durch eine allgemeine "Multiplikation durch wiederholte Addition" Funktion ersetze. Wo die Schleife ersetzt wird durch 'für i in xrange (a): x + = b '. Ich stimme dir zu, dass es eine einfache Schleife ist, und ich kann sehen, wie der Compiler den einen in meiner Frage wegwirft, aber sind Compiler wirklich so magisch, das auch zu tun? – Daffy

Antwort

1

Es scheint sehr wahrscheinlich, dass der Optimierer die Schleife durch eine einzige konstante Berechnung ersetzt hat. Eine Liste der klassischen Schleifenoptimierungen finden Sie unter https://en.wikipedia.org/wiki/Loop_optimization. In diesem Fall führt das vollständige Abwickeln der Schleife und dann das Kombinieren aller Konstanten zu return n (mit x + = 1) oder return n * b (mit x + = b). Unter Verwendung x += i Ergebnisse in return n * (n + 1)/2. (In jedem Fall n die entsprechende obere Schleife gebunden. Wenn i in range(n) Summieren, es ist wirklich nur n-1 statt)

Da dies ein JIT-Compiler ist, kann er dies tun, auch für variable n, obwohl in Ihren Beispielen jeweils n ist eine Konstante, so dass auch Nicht-JIT-Compiler dies tun können.

+1

Nun verdammt Compiler sind nur schlauer als ich dachte. – Daffy