Python Language
Leistungsoptimierung
Suche…
Bemerkungen
Wenn Sie versuchen, die Leistung eines Python-Skripts zu verbessern, sollten Sie in erster Linie den Engpass Ihres Skripts ermitteln und beachten, dass keine Optimierung eine schlechte Wahl der Datenstrukturen oder einen Fehler in Ihrem Algorithmusdesign ausgleichen kann. Sie können Leistungsengpässe identifizieren, indem Sie Ihr Skript profilieren . Zweitens sollten Sie nicht zu früh im Codierprozess auf Kosten der Lesbarkeit / des Designs / der Qualität optimieren. Donald Knuth äußerte sich zur Optimierung wie folgt:
„Wir sollten kleine Wirkungsgrade vergessen, etwa 97% der Zeit: vorzeitige Optimierung ist die Wurzel allen Übels. Dennoch sollten wir unsere Chancen in den kritischen 3% nicht aufgeben. “
Code-Profiling
In erster Linie sollten Sie in der Lage sein, den Engpass Ihres Skripts zu finden und zu beachten, dass keine Optimierung eine schlechte Wahl der Datenstruktur oder einen Fehler in Ihrem Algorithmusdesign ausgleichen kann. Zweitens sollten Sie nicht zu früh im Codierprozess auf Kosten der Lesbarkeit / des Designs / der Qualität optimieren. Donald Knuth äußerte sich zur Optimierung wie folgt:
"Wir sollten kleine Wirkungsgrade vergessen, etwa 97% der Zeit: vorzeitige Optimierung ist die Wurzel allen Übels. Dennoch sollten wir unsere Chancen in diesen kritischen 3% nicht aufgeben."
Um Ihren Code zu profilieren, stehen Ihnen mehrere Werkzeuge zur Verfügung: cProfile
(oder das langsamere profile
) aus der Standardbibliothek, line_profiler
und timeit
. Jeder von ihnen dient einem anderen Zweck.
cProfile
ist ein deterministischer Profiler: Funktionsaufruf, Funktionsrückkehr und Ausnahmeereignisse werden überwacht, und für die Intervalle zwischen diesen Ereignissen (bis zu 0,001 Sekunden) werden genaue Zeitpunkte festgelegt. Die Bibliotheksdokumentation ([ https://docs.python.org/2/library/profile.html __1]) liefert einen einfachen Anwendungsfall
import cProfile
def f(x):
return "42!"
cProfile.run('f(12)')
Oder wenn Sie es vorziehen, Teile Ihres vorhandenen Codes einzuwickeln:
import cProfile, pstats, StringIO
pr = cProfile.Profile()
pr.enable()
# ... do something ...
# ... long ...
pr.disable()
sortby = 'cumulative'
ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
ps.print_stats()
print s.getvalue()
Dadurch werden Ausgaben wie in der folgenden Tabelle erstellt, in denen Sie schnell sehen können, wo Ihr Programm die meiste Zeit verbringt, und die zu optimierenden Funktionen identifizieren.
3 function calls in 0.000 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 <stdin>:1(f)
1 0.000 0.000 0.000 0.000 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
Das Modul line_profiler
([ https://github.com/rkern/line_profiler([1]) ist hilfreich, um eine zeilenweise Analyse des Codes zu erhalten. Dies ist offensichtlich nicht für lange Skripte zu beherrschen, sondern richtet sich an Snippets. Weitere Informationen finden Sie in der Dokumentation. Der einfachste Weg, um loszulegen, ist die Verwendung des Kernprof-Skripts, wie auf der Paketseite erläutert. Beachten Sie, dass Sie die Funktion (en) für das Profil manuell festlegen müssen.
$ kernprof -l script_to_profile.py
kernprof erstellt eine Instanz von LineProfiler und fügt sie mit dem __builtins__
in den __builtins__
Namespace ein. Es wurde geschrieben, um als Dekorateur verwendet zu werden, so dass Sie in Ihrem Skript die Funktionen dekorieren, die Sie mit @profile
profilieren @profile
.
@profile
def slow_function(a, b, c):
...
Das Standardverhalten von Kernprof besteht darin, die Ergebnisse in eine Binärdatei script_to_profile.py.lprof
. Sie können kernprof anweisen, die formatierten Ergebnisse sofort mit der Option [-v / - view] am Terminal anzuzeigen. Ansonsten können Sie die Ergebnisse später wie folgt anzeigen:
$ python -m line_profiler script_to_profile.py.lprof
Schließlich bietet timeit
eine einfache Möglichkeit zum Testen eines timeit
oder eines kleinen Ausdrucks sowohl über die Befehlszeile als auch über die Python-Shell. Dieses Modul beantwortet Fragen, z. B. ist es schneller, ein Listenverständnis auszuführen oder die integrierte list()
wenn Sie einen Satz in eine Liste umwandeln. Suchen Sie nach dem setup
Schlüsselwort oder der Option -s
, um den Setup-Code hinzuzufügen.
>>> import timeit
>>> timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
0.8187260627746582
von einem Terminal
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop