it-swarm.com.de

Wie können Sie ein Python -Skript profilieren?

Project Euler und andere Coding-Wettbewerbe haben oft eine maximale Ausführungszeit oder die Leute geben an, wie schnell ihre jeweilige Lösung ausgeführt wird. Bei Python sind die Ansätze manchmal etwas klug - d. H. Hinzufügen von Timing-Code zu __main__.

Was ist ein guter Weg, um herauszufinden, wie lange ein python -Programm für die Ausführung benötigt?

1166
Chris Lawlor

Python enthält einen Profiler namens cProfile . Es gibt nicht nur die Gesamtlaufzeit, sondern auch die Zeiten für jede Funktion einzeln an und gibt an, wie oft jede Funktion aufgerufen wurde, sodass Sie leicht bestimmen können, wo Sie Optimierungen vornehmen sollten.

Sie können es aus Ihrem Code oder vom Interpreter wie folgt aufrufen:

import cProfile
cProfile.run('foo()')

Noch nützlicher ist, dass Sie das cProfile aufrufen können, wenn Sie ein Skript ausführen:

python -m cProfile myscript.py

Um es noch einfacher zu machen, habe ich eine kleine Batch-Datei namens 'profile.bat' erstellt:

python -m cProfile %1

Also muss ich nur noch laufen:

profile euler048.py

Und ich verstehe:

1007 function calls in 0.061 CPU seconds

Ordered by: standard name
ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    1    0.000    0.000    0.061    0.061 <string>:1(<module>)
 1000    0.051    0.000    0.051    0.000 euler048.py:2(<lambda>)
    1    0.005    0.005    0.061    0.061 euler048.py:2(<module>)
    1    0.000    0.000    0.061    0.061 {execfile}
    1    0.002    0.002    0.053    0.053 {map}
    1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler objects}
    1    0.000    0.000    0.000    0.000 {range}
    1    0.003    0.003    0.003    0.003 {sum}

BEARBEITEN: Der Link zu einer guten Videoressource von PyCon 2013 mit dem Titel Python Profiling wurde aktualisiert
Auch über YouTube .

1243
Chris Lawlor

Vor einiger Zeit habe ich pycallgraph erstellt, das aus Ihrem Python Code eine Visualisierung generiert. Edit: Ich habe das Beispiel aktualisiert, um mit 3.3 zu arbeiten, der neuesten Version zum Zeitpunkt dieses Schreibens.

Nach einem pip install pycallgraph und der Installation von GraphViz können Sie es über die Befehlszeile ausführen:

pycallgraph graphviz -- ./mypythonscript.py

Oder Sie können bestimmte Teile Ihres Codes profilieren:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

In beiden Fällen wird eine pycallgraph.png -Datei ähnlich der folgenden Abbildung erstellt:

enter image description here

391
gak

Es sei darauf hingewiesen, dass die Verwendung des Profilers (standardmäßig) nur für den Haupt-Thread funktioniert und Sie keine Informationen von anderen Threads erhalten, wenn Sie diese verwenden. Dies kann ein kleiner Fehler sein, da dies in der Profiler-Dokumentation nicht erwähnt wird.

Wenn Sie auch Threads profilieren möchten, sollten Sie sich die Funktion threading.setprofile() in den Dokumenten ansehen.

Sie können auch eine eigene Unterklasse threading.Thread erstellen:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

und benutze diese ProfiledThread Klasse anstelle der Standardklasse. Es gibt Ihnen möglicherweise mehr Flexibilität, aber ich bin mir nicht sicher, ob es sich lohnt, insbesondere wenn Sie Code von Drittanbietern verwenden, der Ihre Klasse nicht verwenden würde.

190
Joe Shaw

Das python Wiki ist eine großartige Seite zum Erstellen von Profilen für Ressourcen: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

wie ist das python docs: http://docs.python.org/library/profile.html

wie von Chris Lawlor gezeigt, ist cProfile ein großartiges Werkzeug und kann einfach zum Drucken auf dem Bildschirm verwendet werden:

python -m cProfile -s time mine.py <args>

oder zur Akte:

python -m cProfile -o output.file mine.py <args>

PS> Wenn Sie Ubuntu verwenden, müssen Sie das Python-Profil installieren

Sudo apt-get install python-profiler 

Wenn Sie in eine Datei ausgeben, können Sie mithilfe der folgenden Tools nette Visualisierungen erhalten

PyCallGraph: Ein Tool zum Erstellen von Call-Graph-Bildern
Installieren:

 Sudo pip install pycallgraph

lauf:

 pycallgraph mine.py args

aussicht:

 gimp pycallgraph.png

Sie können verwenden, was immer Sie möchten, um die PNG-Datei anzuzeigen, ich habe Gimp verwendet
Leider bekomme ich oft

dot: graph ist zu groß für cairo-renderer bitmaps. Skalierung um 0,257079 passend

das macht meine bilder unbrauchbar klein. Daher erstelle ich im Allgemeinen svg-Dateien:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS> Stellen Sie sicher, dass Sie graphviz installieren (das das Punktprogramm enthält):

Sudo pip install graphviz

Alternative grafische Darstellung mit gprof2dot über @maxy/@quodlibetor:

Sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg
137
brent.payne

@ Maxys Kommentar zu diese Antwort hat mir so geholfen, dass ich der Meinung bin, dass es seine eigene Antwort verdient: Ich hatte bereits cProfile-generierte .pstats-Dateien und wollte die Dinge nicht mit pycallgraph erneut ausführen Ich habe gprof2dot verwendet und habe hübsche svgs bekommen:

$ Sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg

und BLAM!

Es wird dot verwendet (dasselbe, was pycallgraph verwendet), sodass die Ausgabe ähnlich aussieht. Ich habe den Eindruck, dass gprof2dot weniger Informationen verliert:

gprof2dot example output

129
quodlibetor

Bei der Recherche zu diesem Thema stieß ich auf ein nützliches Tool namens SnakeViz . SnakeViz ist ein webbasiertes Tool zur Visualisierung von Profilen. Es ist sehr einfach zu installieren und zu verwenden. Ich benutze es normalerweise, um eine stat-Datei mit %prun zu generieren und diese dann in SnakeViz zu analysieren.

Die hauptsächliche verwendete Technik ist Sunburst-Diagramm , in dem die Hierarchie der Funktionsaufrufe als Schichten von Bögen und Zeitinformationen angeordnet ist, die in ihrem _ codiert sind.angular Breiten.

Das Beste ist, dass Sie mit dem Diagramm interagieren können. Wenn Sie beispielsweise zoomen möchten, können Sie auf einen Bogen klicken, und der Bogen und seine Nachkommen werden als neuer Sonnendurchbruch vergrößert, um weitere Details anzuzeigen.

enter image description here

61
zaxliu

Ich denke, dass cProfile großartig für die Profilerstellung ist, während kcachegrind großartig für die Visualisierung der Ergebnisse ist. Das pyprof2calltree dazwischen übernimmt die Dateikonvertierung.

_python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree
_

So installieren Sie die erforderlichen Tools (mindestens unter Ubuntu):

_apt-get install kcachegrind
pip install pyprof2calltree
_

Das Ergebnis:

Screenshot of the result

46
Federico

Erwähnenswert ist auch der GUI cProfile Dump Viewer RunSnakeRun . Hier können Sie sortieren und auswählen und dabei die relevanten Teile des Programms vergrößern. Die Größe der Rechtecke im Bild ist proportional zur Zeit. Wenn Sie mit der Maus über ein Rechteck fahren, wird der Anruf in der Tabelle und auf der Karte hervorgehoben. Wenn Sie auf ein Rechteck doppelklicken, wird dieser Bereich vergrößert. Es zeigt Ihnen, wer diesen Teil anruft und wie dieser Teil heißt.

Die beschreibenden Informationen sind sehr hilfreich. Es zeigt Ihnen den Code für dieses Bit, der hilfreich sein kann, wenn Sie mit integrierten Bibliotheksaufrufen arbeiten. Hier erfahren Sie, in welcher Datei und in welcher Zeile Sie den Code finden.

Ich möchte auch darauf hinweisen, dass das OP "Profiling" sagte, aber anscheinend meinte er "Timing". Beachten Sie, dass Programme bei der Profilerstellung langsamer ausgeführt werden.

enter image description here

40
Pete

am einfachsten und am schnellsten um herauszufinden, wo die ganze Zeit hingeht.

1. pip install snakeviz

2. python -m cProfile -o temp.dat <PROGRAM>.py

3. snakeviz temp.dat

Zeichnet ein Kreisdiagramm in einem Browser. Größtes Stück ist die Problemfunktion. Sehr einfach.

36
CodeCabbie

Ein Nice-Profiling-Modul ist der line_profiler (der mit dem Skript kernprof.py aufgerufen wird). Es kann heruntergeladen werden hier .

Meines Wissens nach gibt cProfile nur Informationen über die Gesamtzeit, die für jede Funktion aufgewendet wurde. Einzelne Codezeilen sind also nicht zeitgesteuert. Dies ist ein Problem beim wissenschaftlichen Rechnen, da eine einzelne Zeile oft viel Zeit in Anspruch nehmen kann. Wie ich mich erinnere, hat cProfile auch nicht die Zeit erfasst, die ich in say numpy.dot verbracht habe.

31
Ian Langmore

pprofile

line_profiler (hier bereits vorgestellt) inspirierte auch pprofile , das wie folgt beschrieben wird:

Zeilengranularität, threadbewusster deterministischer und statistischer Pure-Python-Profiler

Es bietet Zeilengranularität als line_profiler, ist reines Python, kann als eigenständiger Befehl oder als Modul verwendet werden und kann sogar Dateien im Callgrind-Format generieren, die einfach mit [k|q]cachegrind analysiert werden können.

vprof

Es gibt auch vprof , ein Python -Paket, das wie folgt beschrieben wird:

[...] Bereitstellung umfangreicher und interaktiver Visualisierungen für verschiedene Python Programmeigenschaften wie Laufzeit und Speichernutzung.

heatmap

29
BenC

Ich habe kürzlich Thunfisch erstellt, um Python Laufzeit- und Importprofile zu visualisieren. Dies kann hier hilfreich sein.

enter image description here

Installieren Sie mit

pip3 install tuna

Erstellen Sie ein Laufzeitprofil

python -mcProfile -o program.prof yourfile.py

oder ein Importprofil (Python 3.7+ erforderlich)

python -X importprofile yourfile.py 2> import.log

Dann führen Sie einfach Thunfisch auf die Datei

tuna program.prof
19
Nico Schlömer

Es gibt viele gute Antworten, aber sie verwenden entweder die Befehlszeile oder ein externes Programm zum Profilieren und/oder Sortieren der Ergebnisse.

Ich habe wirklich eine Möglichkeit verpasst, die ich in meinem IDE (Eclipse-PyDev) verwenden kann, ohne die Befehlszeile zu berühren oder etwas zu installieren. Hier ist es also.

Profilerstellung ohne Kommandozeile

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __== '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

Weitere Informationen finden Sie unter docs oder in anderen Antworten.

13
David Mašek

Nachdem Joe Shaws Antwort bezüglich Multithread-Code nicht erwartungsgemäß funktioniert hat, stellte ich fest, dass die runcall -Methode in cProfile lediglich self.enable()- und self.disable() -Aufrufe um den profilierten Funktionsaufruf ausführt Das können Sie ganz einfach selbst tun und haben den gewünschten Code dazwischen, ohne den vorhandenen Code zu beeinträchtigen.

12
PypeBros

In Virtaals Quelle gibt es eine sehr nützliche Klasse und einen sehr nützlichen Dekorator, mit denen sich das Profiling (auch für bestimmte Methoden/Funktionen) sehr einfach gestalten lässt. Die Ausgabe kann dann sehr komfortabel in KCacheGrind angezeigt werden.

10
Walter

cProfile eignet sich hervorragend zum schnellen Erstellen von Profilen, endete jedoch die meiste Zeit für mich mit den Fehlern. Die Funktion runctx löst dieses Problem, indem sie die Umgebung und die Variablen korrekt initialisiert. Hoffentlich kann sie für jemanden nützlich sein:

import cProfile
cProfile.runctx('foo()', None, locals())
9
Datageek

Ich benutze yappi ( https://code.google.com/p/yappi/ ). Dies ist besonders nützlich in Kombination mit einem RPC-Server, auf dem Sie (auch zum Debuggen) eine Methode zum Starten, Beenden und Drucken von Profilinformationen registrieren, z. auf diese Weise:

@staticmethod
def startProfiler():
    yappi.start()

@staticmethod
def stopProfiler():
    yappi.stop()

@staticmethod
def printProfiler():
    stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
    statPrint = '\n'
    namesArr = [len(str(stat[0])) for stat in stats.func_stats]
    log.debug("namesArr %s", str(namesArr))
    maxNameLen = max(namesArr)
    log.debug("maxNameLen: %s", maxNameLen)

    for stat in stats.func_stats:
        nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
        log.debug('nameAppendSpaces: %s', nameAppendSpaces)
        blankSpace = ''
        for space in nameAppendSpaces:
            blankSpace += space

        log.debug("adding spaces: %s", len(nameAppendSpaces))
        statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
            round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"

    log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
    log.log(1000, statPrint)

Wenn Ihr Programm funktioniert, können Sie den Profiler jederzeit starten, indem Sie die RPC-Methode startProfiler aufrufen und die Profilinformationen in eine Protokolldatei ausgeben, indem Sie printProfiler aufrufen (oder die rpc-Methode ändern, um sie an den Aufrufer zurückzugeben). und bekomme eine solche Ausgabe:

2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
name                                                                                                                                      ncall     ttot    tsub
2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000: 
C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243     4         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4         0.0     0.0
<string>.__new__:8                                                                                                                        220       0.0     0.0
C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0
C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0
<string>.__new__:8                                                                                                                        4         0.0     0.0
C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0
C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0
C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0
C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.Egg.tmp\psutil\__init__.py.cpu_times:1066               4         0.0     0.0 

Es ist möglicherweise für kurze Skripte nicht sehr nützlich, hilft jedoch bei der Optimierung von Prozessen vom Servertyp, insbesondere wenn die printProfiler -Methode im Laufe der Zeit mehrmals aufgerufen werden kann, um z. verschiedene Programmnutzungsszenarien.

6
Mr. Girgitt

Ein neues Tool für die Profilerstellung in Python ist PyVmMonitor: http://www.pyvmmonitor.com/

Es hat einige einzigartige Funktionen wie

  • Verbinden Sie den Profiler mit einem laufenden Programm (CPython)
  • On-Demand-Profilerstellung mit Yappi-Integration
  • Profil auf einer anderen Maschine
  • Unterstützung mehrerer Prozesse (Multiprocessing, Django ...)
  • Live-Sampling/CPU-Ansicht (mit Zeitbereichswahl)
  • Deterministische Profilerstellung durch cProfile/Profil-Integration
  • Analysieren Sie vorhandene PStats-Ergebnisse
  • DOT-Dateien öffnen
  • Programmatischer API-Zugriff
  • Gruppieren Sie die Proben nach Methode oder Linie
  • PyDev-Integration
  • PyCharm-Integration

Hinweis: Es ist kommerziell, aber kostenlos für Open Source.

3
Fabio Zadrozny

Dies hängt davon ab, was Sie bei der Profilerstellung sehen möchten. Einfache Zeitmetriken können durch (bash) angegeben werden.

time python python_prog.py

Sogar '/ usr/bin/time' kann detaillierte Metriken mit dem Flag '--verbose' ausgeben.

Um die von jeder Funktion angegebenen Zeitmetriken zu überprüfen und besser zu verstehen, wie viel Zeit für Funktionen aufgewendet wird, können Sie das in Python integrierte cProfile verwenden.

Bei detaillierteren Metriken wie der Leistung ist die Zeit nicht die einzige Metrik. Sie können sich Gedanken über Speicher, Threads usw. machen.
Profilierungsoptionen:
1. line_profiler ist ein weiterer Profiler, der häufig verwendet wird, um Zeitmessdaten zeilenweise zu ermitteln.
2. memory_profiler ist ein Tool zum Profilieren der Speichernutzung.
3. heapy (aus dem Projekt Guppy) Profilieren Sie, wie Objekte im Heap verwendet werden.

Dies sind einige der häufigsten, die ich benutze. Aber wenn Sie mehr darüber erfahren möchten, lesen Sie dieses Buch book Es ist ein ziemlich gutes Buch für den Einstieg mit Blick auf die Leistung. Sie können mit Cython und JIT (Just-in-Time) kompiliertem Python zu fortgeschrittenen Themen übergehen.

3
VishalMishra

Wollten Sie schon immer wissen, was zum Teufel das Skript python tut? Rufen Sie die Inspect-Shell auf. Mit Inspect Shell können Sie globale Elemente drucken/ändern und Funktionen ausführen, ohne das ausgeführte Skript zu unterbrechen. Jetzt mit Auto-Vervollständigung und Befehlsverlauf (nur unter Linux).

Inspect Shell ist kein Debugger im PDB-Stil.

https://github.com/amoffat/Inspect-Shell

Sie könnten das (und Ihre Armbanduhr) verwenden.

3
Colonel Panic

Hinzufügen zu https://stackoverflow.com/a/582337/1070617 ,

Ich habe dieses Modul geschrieben, mit dem Sie cProfile verwenden und die Ausgabe einfach anzeigen können. Mehr hier: https://github.com/ymichael/cprofilev

$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.

Siehe auch: http://ymichael.com/2014/03/08/profiling-python-with-cprofile.html wie die gesammelten Statistiken sinnvoll sind.

3
michael

Es gibt auch einen statistischen Profiler namens statprof . Es ist ein Sampling-Profiler, der Ihrem Code einen minimalen Overhead verleiht und zeilenbasierte (nicht nur funktionsbasierte) Timings liefert. Es eignet sich eher für Echtzeitanwendungen wie Spiele, ist jedoch möglicherweise weniger präzise als cProfile.

Die Version in pypi ist ein bisschen alt, daher kann sie mit pip installiert werden, indem das Git-Repository angegeben wird:

pip install git+git://github.com/bos/[email protected]

Sie können es so ausführen:

import statprof

with statprof.profile():
    my_questionable_function()

Siehe auch https://stackoverflow.com/a/10333592/320036

1
z0r

Wenn ich nicht auf dem Server root bin, benutze ich lsprofcalltree.py und starte mein Programm wie folgt:

python lsprofcalltree.py -o callgrind.1 test.py

Dann kann ich den Bericht mit jeder Callgrind-kompatiblen Software wie qcachegrind öffnen

0
Vincent Fenet

Die einzige (und einfachste) Lösung für Terminals, wenn all diese ausgefallenen Benutzeroberflächen nicht installiert oder ausgeführt werden können:
ignoriere cProfile vollständig und ersetze es durch pyinstrument, wodurch der Baum der Aufrufe direkt nach der Ausführung gesammelt und angezeigt wird.

Installieren:

$ pip install pyinstrument

Profil und Anzeigeergebnis:

$ python -m pyinstrument ./prog.py

Funktioniert mit Python2 und 3.

0
Francois

gprof2dot_magic

Magic-Funktion für gprof2dot zum Profilieren einer Python -Anweisung als DOT-Diagramm in JupyterLab oder Jupyter Notebook.

enter image description here

GitHub-Repo: https://github.com/mattijn/gprof2dot_magic

Installation

Stellen Sie sicher, dass Sie das Python -Paket gprof2dot_magic haben.

pip install gprof2dot_magic

Die Abhängigkeiten gprof2dot und graphviz werden ebenfalls installiert

Nutzung

Laden Sie zum Aktivieren der Magic-Funktion zuerst das gprof2dot_magic -Modul

%load_ext gprof2dot_magic

und dann eine beliebige Zeilenanweisung als DOT-Diagramm wie folgt profilieren:

%gprof2dot print('hello world')

enter image description here

0
Mattijn