Geschwindigkeit der Listeneinschlussnotation in Python

Ist die Notation zur Aufnahme von Listen schnell?

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
  2. testfunc2: 1 + Anhängen wird zu einem Objekt gemacht
  3. testfunc3: Listeneinschlussnotation

Vorbereitung

# 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]

Messung

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

Ergebnis

  1. 1.73 s
  2. 1.08 s
  3. 697 ms

Fazit

** 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.


Zerlegen und bestätigen Sie den Grund

Lassen Sie uns untersuchen, warum dieses Ergebnis durch Zerlegen jeder Funktion mithilfe des dis-Moduls von Python erzielt wird.

Zerlegen

>>> 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        

Kommentar

Von der obigen Ausgabe ist FOR_ITER bis JUMP_ABSOLUTE eine Schleife, die 10.000.000 Mal aufgerufen wird.

Vergleich von testfunc1 und testfunc2

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.

Vergleich von testfunc2 und testfunc3

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.

Referenz

Dieser Artikel wurde unter Bezugnahme auf die folgenden Artikel geschrieben.


Nachtrag

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.

Ergebnis

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.

Python 3.3.3 + Bereichsfunktion nicht verwendet

>>> %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.

Fazit

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

Geschwindigkeit der Listeneinschlussnotation in Python
Python> Verständnis / Inklusive Notation> Listenverständnis
Python-Übung 2 - List Inclusion Notation
Python-Einschlussnotation
Python-Einschlussnotation
Listeneinschlussnotation
[Python] -Liste
Über die Einschlussnotation von Python
Python-Grundlagen: Liste
Hinweis: Listeneinschlussnotation
Python-Listenmanipulation
Inklusive Notation von Python (über Liste und Generatorausdruck) [zusätzlich]
Sortierte Liste in Python
[Python] Listenverständnis Verschiedene Möglichkeiten zum Erstellen einer Liste
Liste der Python-Module
Python> Liste> verlängern () oder + =
Sortierte Liste in Python
FizzBuzz in Listeneinschlussnotation
Python ~ Grammatikgeschwindigkeit lernen ~
[Einführung in die Udemy Python3 + -Anwendung] 60. Listeneinschlussnotation
Filterliste in Python
Python unittest assertXXX Liste
Python3-Memo vom Typ Liste / Wörterbuch
[Memo] Python 3-Listensortierung
Liste der Python-APIs für OpenCV3
Python-Fehlerliste (Japanisch)
Inklusive Notation, nicht nur eine Liste
Die findähnliche Sache der Liste in Python
Ich habe die Geschwindigkeit der Listeneinschlussnotation für und während mit Python2.7 gemessen.
Liste der Python-Ausnahmeklassen
Schnelle Sortierung 2 | Einfach mit Listeneinschlussnotation
Liste mit Python initialisieren
Listenverständnis, da operator.methodcaller nicht mit Python 2.5 verwendet werden kann
Python3-Einschlussnotation (Liste, Wörterbuch), die ich irgendwo gesehen habe
Python-Handspiel (zweidimensionale Liste)
python3 Messen Sie die Verarbeitungsgeschwindigkeit.
Python-Liste, für Anweisung, Wörterbuch
Zusammenfassung der Python3-Listenoperationen
Geschwindigkeitsvergleich von Python, Java, C ++
[Python] Liste in Pandas konvertieren [Pandas]
ToDo-Listenerstellung [Python Django]
Geben Sie mehrere Listenindizes an (Python)
Python-Grundkurs (5 List Taple)
Messen Sie die WLAN-Geschwindigkeit mit Python
Ich habe die Geschwindigkeit der Referenz des Pythons in der Liste und die Referenz der Wörterbucheinbeziehung aus der In-Liste verglichen.
[Python] Kopie einer mehrdimensionalen Liste
[Einführung in Python] <Liste> [Bearbeiten: 22.02.2020]
Python-Liste und Tapples und Kommas
Paiza Python Primer 4: Grundlagen der Liste
Python-Listeneinschlussnotation und Generator
[Python / PyQ] 4. Liste zur Anweisung
Python #Liste für Super-Anfänger
Abrufen von Listenelementen in Python
[Road to Intermediate Python] Verwenden Sie die if-Anweisung in der Listeneinschlussnotation
Extrahieren Sie mehrere Listenduplikate in Python
Unterschied zwischen list () und [] in Python
[Python] Verwalten Sie Funktionen in einer Liste
Ausgabe 2017 Premium Friday List in Python