Wie im Auftakt-Eintrag beschrieben, handelt dieser Post von Maßnahmen und Erkenntnissen bei der Performance-Optimierung von Jython und Django.
Als erstes Testszenario für die Optimierung verwendeten wir eine normale Datenbankabfrage über den Django Object Relational Mapper (ORM).
len(Foo.objects.all())
Zum Profiling der Abfrage nutzten wir die Python-Bordwerkzeuge profile und pstats. Nach einem ersten Profiling zeigte sich die deepcopy()-Funktion mit 6218 Aufrufen und über einer halben Sekunde kumulierter Laufzeit als erster Ansatzpunkt.
In zwei internen Funktionen wurden Dictionaries in try/except-Statements verwendet. Laut den Python-Tipps zum Umgang mit Dictionaries ist dies ein sinnvolles Vorgehen, falls zu beschreibende Schlüssel erwartungsgemäß schon im Dictionary vorhanden sind. Hier jedoch wird das Dictionary mit neuen Werten gefüllt, daher war das Auftreten von Exceptions eher die Regel als die Ausnahme. Zu prüfen, ob ein Schlüssel schon vorhanden ist, ist in diesem Fall also effizienter (und mehr pythonic).
Dieser Fall stellt sich am Beispiel der Funktion _keep_alive() aus Lib/copy.py wie folgt dar:
try:
memo[id(memo)].append(x)
except KeyError:
memo[id(memo)]=[x]
Diese Konstruktion wird umgeschrieben zu
if id(memo) in memo:
memo[id(memo)].append(x)
else:
memo[id(memo)]=[x]
Weiter fällt auf, dass id(memo) in jedem Zweig der if/else-Anweisung doppelt angefasst werden muss. Aus diesem Grund bietet sich die Auslagerung des Ausdruckes in eine gemeinsame Referenz an. Die zeitliche Einsparung ist vergleichsweise gering, jedoch preisgünstig, weil man ohnehin schon den Code anfasst.
id_memo = id(memo)
if id_memo in memo:
memo[id_memo].append(x)
else:
memo[id_memo] = [x]
Wirkung dieser einfachen Maßnahmen: Eine Laufzeitreduzierung von 0.36 auf 0.08 sec in _keep_alive() und von 0.3 auf 0.1 sec in _deepcopy_tuple(), in der eine ähnliche try/except-Konstruktion vorhanden war.
Als nächsten Ansatzpunkt für Optimierungen fielen uns JSON-Felder ins Auge, insbesondere deren Konvertierung beim Datenbankzugriff. Mehr dazu im nächsten Blogeintrag.
Tags: apache, database, Django, engine, java, jython, optimierung, optimization, performance, profiling, Python, template, tomcat
This entry was posted on Wednesday, April 14th, 2010 at 2:48 pm and is filed under Django, Frameworks, Python. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.