Normalerweise benutze ich den Shell-Befehl time
. Mein Zweck ist es zu testen, ob Daten klein, mittel, groß oder sehr groß sind, wie viel Zeit und Speicherplatz benötigt werden.
Irgendwelche Tools für Linux oder nur Python, um dies zu tun?
Antworten:
Schauen Sie sich timeit , den Python-Profiler und den Pycallgraph an . Schauen Sie sich auch den Kommentar unten an,nikicc
indem Sie " SnakeViz " erwähnen . Es gibt Ihnen eine weitere Visualisierung von Profildaten, die hilfreich sein kann.
def test():
"""Stupid test function"""
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
# For Python>=3.5 one can also write:
print(timeit.timeit("test()", globals=locals()))
Im Wesentlichen können Sie den Python-Code als Zeichenfolgenparameter übergeben. Er wird in der angegebenen Häufigkeit ausgeführt und gibt die Ausführungszeit aus. Die wichtigen Teile aus den Dokumenten :
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
Erstellen Sie eineTimer
Instanz mit der angegebenen Anweisung, Setup - Code und Timer - Funktion und führen Sie seinetimeit
Methode mit Nummer Hinrichtungen. Das optionale globale Argument gibt einen Namespace an, in dem der Code ausgeführt werden soll.
... und:
Timer.timeit(number=1000000)
Zeit Anzahl Ausführungen der Hauptaussage. Dadurch wird die Setup-Anweisung einmal ausgeführt und anschließend die Zeit zurückgegeben, die zum mehrmaligen Ausführen der Hauptanweisung benötigt wird, gemessen in Sekunden als Float. Das Argument ist die Häufigkeit, mit der die Schleife durchlaufen wird, standardmäßig eine Million. Die Hauptanweisung, die Setup-Anweisung und die zu verwendende Timer-Funktion werden an den Konstruktor übergeben.Hinweis: Wird standardmäßig während des Timings
timeit
vorübergehend ausgeschaltetgarbage collection
. Der Vorteil dieses Ansatzes besteht darin, dass unabhängige Timings vergleichbarer werden. Dieser Nachteil besteht darin, dass GC ein wichtiger Bestandteil der Leistung der gemessenen Funktion sein kann. In diesem Fall kann GC als erste Anweisung in der Setup- Zeichenfolge wieder aktiviert werden . Zum Beispiel:
timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()
Profilierungs geben Ihnen einen viel detaillierteren Vorstellung davon , was vor sich geht. Hier ist das "sofortige Beispiel" aus den offiziellen Dokumenten :
import cProfile
import re
cProfile.run('re.compile("foo|bar")')
Welches wird Ihnen geben:
197 function calls (192 primitive calls) in 0.002 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.001 0.001 <string>:1(<module>)
1 0.000 0.000 0.001 0.001 re.py:212(compile)
1 0.000 0.000 0.001 0.001 re.py:268(_compile)
1 0.000 0.000 0.000 0.000 sre_compile.py:172(_compile_charset)
1 0.000 0.000 0.000 0.000 sre_compile.py:201(_optimize_charset)
4 0.000 0.000 0.000 0.000 sre_compile.py:25(_identityfunction)
3/1 0.000 0.000 0.000 0.000 sre_compile.py:33(_compile)
Beide Module sollen Ihnen eine Vorstellung davon geben, wo Sie nach Engpässen suchen müssen.
profile
Schauen Sie sich auch diesen Beitrag an, um die Ausgabe von in den Griff zu bekommen
Dieses Modul verwendet graphviz, um Callgraphs wie die folgenden zu erstellen:
Sie können anhand der Farbe leicht erkennen, welche Pfade am häufigsten verwendet werden. Sie können sie entweder mit der Pycallgraph-API oder mit einem gepackten Skript erstellen:
pycallgraph graphviz -- ./mypythonscript.py
Der Overhead ist jedoch ziemlich beträchtlich. Bei bereits lang laufenden Prozessen kann das Erstellen des Diagramms einige Zeit dauern.
Ich benutze einen einfachen Dekorateur, um die Funkzeit zu messen
def st_time(func):
"""
st decorator to calculate the total time of a func
"""
def st_func(*args, **keyArgs):
t1 = time.time()
r = func(*args, **keyArgs)
t2 = time.time()
print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
return r
return st_func
Das timeit
Modul war langsam und komisch, also schrieb ich Folgendes:
def timereps(reps, func):
from time import time
start = time()
for i in range(0, reps):
func()
end = time()
return (end - start) / reps
Beispiel:
import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)
Für mich heißt es:
python can do 40925 os.listdir('/') per second
Dies ist eine primitive Art von Benchmarking, aber es ist gut genug.
Normalerweise sehe ich schnell time ./script.py
, wie lange es dauert. Das zeigt Ihnen jedoch nicht den Speicher, zumindest nicht als Standard. Sie können verwenden /usr/bin/time -v ./script.py
, um viele Informationen abzurufen, einschließlich der Speichernutzung.
/usr/bin/time
mit -v
Option in vielen Distributionen nicht standardmäßig verfügbar ist und installiert werden muss. sudo apt-get install time
in debian, ubuntu usw. pacman -S time
archlinux
Memory Profiler für alle Ihre Speicheranforderungen.
https://pypi.python.org/pypi/memory_profiler
Führen Sie eine Pip-Installation aus:
pip install memory_profiler
Importieren Sie die Bibliothek:
import memory_profiler
Fügen Sie dem Element, das Sie profilieren möchten, einen Dekorateur hinzu:
@profile
def my_func():
a = [1] * (10 ** 6)
b = [2] * (2 * 10 ** 7)
del b
return a
if __name__ == '__main__':
my_func()
Führen Sie den Code aus:
python -m memory_profiler example.py
Erhalten Sie die Ausgabe:
Line # Mem usage Increment Line Contents
==============================================
3 @profile
4 5.97 MB 0.00 MB def my_func():
5 13.61 MB 7.64 MB a = [1] * (10 ** 6)
6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7)
7 13.61 MB -152.59 MB del b
8 13.61 MB 0.00 MB return a
Beispiele stammen aus den oben verlinkten Dokumenten.
Schauen Sie sich die Nase und eines ihrer Plugins an, dieses insbesondere.
Nach der Installation ist Nase ein Skript in Ihrem Pfad, das Sie in einem Verzeichnis aufrufen können, das einige Python-Skripte enthält:
$: nosetests
Dadurch werden alle Python-Dateien im aktuellen Verzeichnis durchsucht und alle Funktionen ausgeführt, die als Test erkannt werden. Beispielsweise werden alle Funktionen mit dem Wort test_ im Namen als Test erkannt.
Sie können also einfach ein Python-Skript namens test_yourfunction.py erstellen und so etwas darin schreiben:
$: cat > test_yourfunction.py
def test_smallinput():
yourfunction(smallinput)
def test_mediuminput():
yourfunction(mediuminput)
def test_largeinput():
yourfunction(largeinput)
Dann musst du rennen
$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py
Verwenden Sie zum Lesen der Profildatei diese Python-Zeile:
python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"
nose
setzt auf hotshot. Es wird seit Python 2.5 nicht mehr gepflegt und nur noch "für den speziellen Gebrauch" aufbewahrt
Seien Sie vorsichtig, es timeit
ist sehr langsam, es dauert 12 Sekunden auf meinem mittleren Prozessor, um nur zu initialisieren (oder vielleicht die Funktion auszuführen). Sie können diese akzeptierte Antwort testen
def test():
lst = []
for i in range(100):
lst.append(i)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second
Für eine einfache Sache, die ich time
stattdessen verwenden werde, gibt es auf meinem PC das Ergebnis zurück0.0
import time
def test():
lst = []
for i in range(100):
lst.append(i)
t1 = time.time()
test()
result = time.time() - t1
print(result) # 0.000000xxxx
timeit
führt Ihre Funktion viele Male aus, um das Rauschen zu mitteln. Die Anzahl der Wiederholungen ist eine Option, siehe Benchmarking-Laufzeiten in Python oder den späteren Teil der akzeptierten Antwort auf diese Frage.
snakeviz
interaktiver Viewer für cProfile
https://github.com/jiffyclub/snakeviz/
cProfile wurde unter https://stackoverflow.com/a/1593034/895245 erwähnt und snakeviz wurde in einem Kommentar erwähnt , aber ich wollte es weiter hervorheben.
Es ist sehr schwierig, die Programmleistung nur durch Betrachten cprofile
/ Ausgeben zu debuggen pstats
, da nur die Gesamtzeiten pro Funktion sofort verfügbar sind.
Im Allgemeinen müssen wir jedoch eine verschachtelte Ansicht sehen, die die Stapelspuren jedes Aufrufs enthält, um die wichtigsten Engpässe tatsächlich leicht zu finden.
Und genau das bietet snakeviz über seine Standardansicht "Eiszapfen".
Zuerst müssen Sie die cProfile-Daten in eine Binärdatei sichern, und dann können Sie darauf snakeviz
pip install -u snakeviz
python -m cProfile -o results.prof myscript.py
snakeviz results.prof
Dadurch wird eine URL zu stdout gedruckt, die Sie in Ihrem Browser öffnen können und die die gewünschte Ausgabe enthält, die folgendermaßen aussieht:
und Sie können dann:
Profilorientiertere Frage: Wie können Sie ein Python-Skript profilieren?
Wenn Sie keinen Boilerplate-Code für die Zeit schreiben und einfach zu analysierende Ergebnisse erhalten möchten, werfen Sie einen Blick auf Benchmarkit . Außerdem wird der Verlauf früherer Läufe gespeichert, sodass die gleiche Funktion im Verlauf der Entwicklung leicht verglichen werden kann.
# pip install benchmarkit
from benchmarkit import benchmark, benchmark_run
N = 10000
seq_list = list(range(N))
seq_set = set(range(N))
SAVE_PATH = '/tmp/benchmark_time.jsonl'
@benchmark(num_iters=100, save_params=True)
def search_in_list(num_items=N):
return num_items - 1 in seq_list
@benchmark(num_iters=100, save_params=True)
def search_in_set(num_items=N):
return num_items - 1 in seq_set
benchmark_results = benchmark_run(
[search_in_list, search_in_set],
SAVE_PATH,
comment='initial benchmark search',
)
Druckt auf das Terminal und gibt eine Liste der Wörterbücher mit Daten für den letzten Lauf zurück. Befehlszeilen-Einstiegspunkte sind ebenfalls verfügbar.
Wenn Sie sich ändern N=1000000
und erneut ausführen
python -m cProfile -o results.prof myscript.py
. Die oputput-Datei kann dann in einem Browser von einem Programm namens SnakeViz unter Verwendung vonsnakeviz results.prof