18 Profiling und Timing
Die Funktion time.time() gibt die aktuelle Zeit als Unix-Timestamp in Sekunden zurück. Sie ist allerdings nicht ideal für präzise Zeitmessungen, weil sie durch folgende Faktoren beeinflusst wird:
time.time() basiert auf der Systemuhr, die je nach Betriebssystem nicht hochauflösend ist.time.time() oft nur eine Genauigkeit von etwa 15,6 Millisekunden.time.time() springen oder rückwärtslaufen.time.time() ist hauptsächlich für das Abrufen der aktuellen Uhrzeit gedacht, nicht für Hochpräzisionsmessungen.Die Funktion time.perf_counter() ist speziell für hochpräzise Zeitmessungen gedacht:
import time
# Ungenau:
start = time.time() # Nur geeignet um aktuelle Zeit zu erhalten
time.sleep(1)
end = time.time()
print(end - start)
# Genau:
start = time.perf_counter()
time.sleep(1)
end = time.perf_counter()
print(end - start)
unittest-Modul (im Standardpaket enthalten).pytest, nose2 (externe Pakete).unittestimport unittest
# Beispiel-Funktion: Addiert zwei Zahlen
def add_numbers(a, b):
return a + b
# Testklasse
class TestAddNumbers(unittest.TestCase):
def test_positive_numbers(self):
self.assertEqual(add_numbers(2, 3), 5)
def test_negative_numbers(self):
self.assertEqual(add_numbers(-1, -1), -2)
def test_zero(self):
self.assertEqual(add_numbers(0, 0), 0)
# Hauptprogramm für Unit-Tests
if __name__ == '__main__':
unittest.main()
unittest.TestCaseassertEqual(a, b)assertNotEqual(a, b)assertTrue(x)assertFalse(x)assertIsNone(x)assertRaises(Exception, func, args...)Performance-Engpässe (Bottlenecks) im Code finden.
cProfile (Standardmodul, robust)timeit (für kleinere Snippets)line_profiler (extern, detailliert)py-spy, snakeviz, yappi (externe Visualisierung)cProfileimport cProfile
# Rechenintensive Beispiel-Funktion
def compute_heavy_task():
total = 0
for i in range(100000):
total += i ** 2
return total
# Führe Profiling durch
cProfile.run('compute_heavy_task()')
timeitimport timeit
# Zeitmessung für einfachen Ausdruck
code = "sum([i*i for i in range(1000)])"
duration = timeit.timeit(stmt=code, number=1000)
print(f"Durchschnittszeit: {duration:.4f} Sekunden")
pip install line_profiler
# sample.py
# Mit @profile markierte Funktion
@profile
def compute():
total = 0
for i in range(10000):
total += i ** 2
return total
# Ausführen mit line_profiler
kernprof -l sample.py
python -m line_profiler sample.py.lprof
Was es bedeutet:
Ablauf:
Vorteile:
pytest für eleganteres Testing (nutzt assert statt Methoden)Was pytest auszeichnet:
Sehr beliebt wegen seiner einfachen Syntax.
Statt wie in unittest Methoden wie assertEqual(a, b) zu verwenden, nutzt man einfach:
assert a == b
Beispiel mit pytest:
# test_math.py
def add(a, b):
return a + b
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
Warum es eleganter ist:
pytest-cov, hypothesis uvm.Warum das wichtig ist:
Praxis-Tipp:
Wenn man z. B. ein Programm für Logfile-Analyse entwickelt:
Tools wie cProfile, timeit, line_profiler sollten mit realistischen Inputs verwendet werden, um aussagekräftige Ergebnisse zu liefern.
Was das bedeutet:
Wie man es macht:
Beispiel mit pytest:
import time
def test_performance():
start = time.time()
result = sum(i*i for i in range(100000))
duration = time.time() - start
assert duration < 0.5 # z. B. Maximal 0.5 Sekunden erlaubt
Vorteile:
unittest oder pytest in VS CodeCtrl+Shift+P → "Python: Interpreter auswählen").Ctrl+Shift+PPython: Discover Testsunittest, pytest oder nose als Framework auswählen.Python: Run All Tests oder Run Test direkt über dem Test mit dem kleinen „Play“-Icon.VS Code erkennt
pytestautomatisch, wenn die Datei mittest_*.pybeginnt undassert-Statements enthält.
Run → Start Debugging ausführen.cProfile-Ausgaben direkt im Terminal oder über Plugins visualisieren lassen.| Aktion | Shortcut |
|---|---|
| Testdatei ausführen | Ctrl+F5 oder ▶ oben |
| Terminal öffnen | `Ctrl+`` |
| Befehlspalette öffnen | Ctrl+Shift+P |
| Tests entdecken | Python: Discover Tests |
| Nur einen Test ausführen | Rechtsklick > Run Test |