In Python 2.6.6 haben wir die Ausführungszeiten der folgenden 1,2,3-Methoden verglichen, um 10.000.000 Ganzzahlen anzuhängen. Zusammenfassend war die Notation der Listeneinbeziehung von 3 so schnell wie erwartet. Wie ich im Postscript geschrieben habe, können die hier beschriebenen Inhalte auch auf die Serien Python 2.7 und 3.3 angewendet werden.
# 1. testfunc1:Bereiten Sie eine leere Liste vor und hängen Sie sie an
def testfunc1(rangelist):
templist = []
for temp in rangelist:
templist.append(temp)
# 2. testfunc2: 1+Objektivieren anhängen
def testfunc2(rangelist):
templist = []
append = templist.append
for temp in rangelist:
append(temp)
# 3. testfunc3:Listeneinschlussnotation
def testfunc3(rangelist):
templist = [temp for temp in rangelist]
Verwenden Sie den Befehl% timeit von IPython, um "Extrahieren Sie den schnellsten von 3 Läufen" zehnmal auszuführen, um die durchschnittliche Laufzeit zu ermitteln.
# 10,000,Erstellen Sie eine Liste mit 000 Ganzzahlen
>>> rangelist = range(1,10000000)
>>> %timeit -n 10 -r 3 testfunc1(rangelist)
10 loops, best of 3: 1.73 s per loop
>>> %timeit -n 10 -r 3 testfunc2(rangelist)
10 loops, best of 3: 1.08 s per loop
>>> %timeit -n 10 -r 3 testfunc3(rangelist)
10 loops, best of 3: 697 ms per loop
** In einer Schleife, in der die Ausführungszeit ein Problem darstellt, ist es besser, die Listeneinschlussnotation wie 3 zu verwenden. ** **. ** Auch wenn Sie die Listeneinschlussnotation nicht verwenden, ist es besser, die Referenz der Append-Methode wie in 2 im Voraus in die Variable einzufügen. ** **.
Beachten Sie, dass die zweite Methode zum vorherigen Einfügen der Methodenreferenz in eine Variable auch verwendet werden kann, um die Schleifenausführungszeit außer der Listenerstellung zu verkürzen.
Lassen Sie uns untersuchen, warum dieses Ergebnis durch Zerlegen jeder Funktion mithilfe des dis-Moduls von Python erzielt wird.
>>> import dis
>>> dis.dis(testfunc1)
3 0 BUILD_LIST 0
3 STORE_FAST 1 (templist)
4 6 SETUP_LOOP 27 (to 36)
9 LOAD_FAST 0 (rangelist)
12 GET_ITER
>> 13 FOR_ITER 19 (to 35)
16 STORE_FAST 2 (temp)
5 19 LOAD_FAST 1 (templist)
22 LOAD_ATTR 0 (append)
25 LOAD_FAST 2 (temp)
28 CALL_FUNCTION 1
31 POP_TOP
32 JUMP_ABSOLUTE 13
>> 35 POP_BLOCK
>> 36 LOAD_CONST 0 (None)
39 RETURN_VALUE
>>> dis.dis(testfunc2)
9 0 BUILD_LIST 0
3 STORE_FAST 1 (templist)
10 6 LOAD_FAST 1 (templist)
9 LOAD_ATTR 0 (append)
12 STORE_FAST 2 (append)
11 15 SETUP_LOOP 24 (to 42)
18 LOAD_FAST 0 (rangelist)
21 GET_ITER
>> 22 FOR_ITER 16 (to 41)
25 STORE_FAST 3 (temp)
12 28 LOAD_FAST 2 (append)
31 LOAD_FAST 3 (temp)
34 CALL_FUNCTION 1
37 POP_TOP
38 JUMP_ABSOLUTE 22
>> 41 POP_BLOCK
>> 42 LOAD_CONST 0 (None)
45 RETURN_VALUE
>>> dis.dis(testfunc3)
16 0 BUILD_LIST 0
3 DUP_TOP
4 STORE_FAST 1 (_[1])
7 LOAD_FAST 0 (rangelist)
10 GET_ITER
>> 11 FOR_ITER 13 (to 27)
14 STORE_FAST 2 (temp)
17 LOAD_FAST 1 (_[1])
20 LOAD_FAST 2 (temp)
23 LIST_APPEND
24 JUMP_ABSOLUTE 11
>> 27 DELETE_FAST 1 (_[1])
30 STORE_FAST 3 (templist)
33 LOAD_CONST 0 (None)
36 RETURN_VALUE
Von der obigen Ausgabe ist FOR_ITER bis JUMP_ABSOLUTE eine Schleife, die 10.000.000 Mal aufgerufen wird.
In testfunc1 können Sie sehen, dass 22 LOAD_ATTR die Append-Methode des Listenobjekts aufruft und dann 28 CALL_FUNCTION tatsächlich anhängt.
testfunc1 für Schleife
>> 13 FOR_ITER 19 (to 35)
16 STORE_FAST 2 (temp)
5 19 LOAD_FAST 1 (templist)
22 LOAD_ATTR 0 (append)
25 LOAD_FAST 2 (temp)
28 CALL_FUNCTION 1
31 POP_TOP
32 JUMP_ABSOLUTE 13
Andererseits befindet sich LOAD_ATTR in testfunc2 außerhalb der Schleife, und innerhalb der Schleife ruft 28 LOAD_FAST die Append-Methode auf, und dann führt 34 CALL_FUNCTION Append aus.
testfunc2 für Schleife
>> 22 FOR_ITER 16 (to 41)
25 STORE_FAST 3 (temp)
12 28 LOAD_FAST 2 (append)
31 LOAD_FAST 3 (temp)
34 CALL_FUNCTION 1
37 POP_TOP
38 JUMP_ABSOLUTE 22
LOAD_ATTR und LOAD_FAST dauern länger als LOAD_ATTR. Daher hat testfunc2 mit LOAD_ATTR außerhalb der Schleife eine kürzere Ausführungszeit als testfunc1 mit LOAD_ATTR innerhalb der Schleife.
In testfunc2 habe ich die Append-Methode mit 28 LOAD_FAST geladen und dann mit 34 CALL_FUNCTION aufgerufen. Auf der anderen Seite ruft testfunc3 23 LIST_APPEND auf, einen Nur-Listen-Prozess, und es gibt keine CALL_FUNCTION.
testfunc3 für Schleife
>> 11 FOR_ITER 13 (to 27)
14 STORE_FAST 2 (temp)
17 LOAD_FAST 1 (_[1])
20 LOAD_FAST 2 (temp)
23 LIST_APPEND
24 JUMP_ABSOLUTE 11
Bei CALL_FUNCTION und LIST_APPEND ist der Aufruf von LIST_APPEND, einem reinen Listenprozess, schneller (CALL_FUNCTION verfügt über verschiedene Prozesse, da es sich um einen allgemeinen Funktionsaufruf handelt). Daher hat testfunc3 mit CALL_FUNCTION, das durch LIST_APPEND ersetzt wurde, eine kürzere Ausführungszeit als testfunc2 mit CALL_FUNCTION in der Schleife.
Dieser Artikel wurde unter Bezugnahme auf die folgenden Artikel geschrieben.
Ich habe auch Python 2.7 und 3.3 verglichen, um sicherzustellen, dass es bei dem oben genannten nicht nur um Python 2.6 geht. Da ich die Maschine gewechselt habe, macht es keinen Sinn, sie mit der oben genannten Ausführungszeit zu vergleichen.
Python 2.7.4
>>> %timeit -n 5 testfunc1()
5 loops, best of 3: 974 ms per loop
>>> %timeit -n 5 testfunc2()
5 loops, best of 3: 737 ms per loop
>>> %timeit -n 5 testfunc3()
5 loops, best of 3: 430 ms per loop
Python 3.3.3
>>> %timeit -n 5 testfunc1()
5 loops, best of 3: 1.21 s per loop
>>> %timeit -n 5 testfunc2()
5 loops, best of 3: 815 ms per loop
>>> %timeit -n 5 testfunc3()
5 loops, best of 3: 639 ms per loop
Nun, Python3 ist langsamer ... Übrigens scheint es in Python3 so zu sein, dass die Bereichsfunktion einen Iterator anstelle einer Liste zurückgibt. Lassen Sie uns also eine Liste erstellen und ausführen, ohne die Bereichsfunktion zu verwenden.
>>> %timeit -n 5 testfunc1()
5 loops, best of 3: 1.19 s per loop
>>> %timeit -n 5 testfunc2()
5 loops, best of 3: 611 ms per loop
>>> %timeit -n 5 testfunc3()
5 loops, best of 3: 429 ms per loop
Ich bin immer noch misstrauisch gegenüber testfunc1, aber jetzt kann ich testfunc2 und testfunc3 in ungefähr der gleichen Zeit wie Python 2.7.4 ausführen.
Für Python 2.7 und Python 3.3 für 1, 2 und 3 gilt das Gleiche wie für Python 2.6.
Recommended Posts