X

Überprüfung der Performance von Funktionen in Python mit timeit

In einem meiner letzten Blogartikel wurde ich von Alex in den Kommentaren auf eine mögliche Verbesserung hingewiesen.

Und zwar ging es um den folgenden Codeschnipsel, mit welchem ich den Unix-Timestamp der vollen Stunde, bei Angabe eines beliebigen Timestamps, berechnet habe:

import time
import datetime

timestamp = '1387965457'  # der Original-Timestamp
datetimetuple = datetime.datetime.fromtimestamp(int(timestamp))  # Umwandeln in ein datetime-Objekt
print datetimetuple
datetime_fullhour = datetime.datetime(  # Erstellen eines neuen datetime-Objekts, in welchem Minuten und Sekunden genullt sind
    datetimetuple.year,
    datetimetuple.month,
    datetimetuple.day,
    datetimetuple.hour)
print datetime_fullhour
timestamp_fullhour = int(time.mktime(datetime_fullhour.timetuple()))  # Umwandeln des neuen Objekts in einen Unix-Timestamp
print timestamp_fullhour

Der Code von Alex sieht hingegeben bedeutend einfacher aus:

fullhour = timestamp - (timestamp % (60*60))

Zur Überprüfung, ob beide Herangehensweisen wirklich das selbe Ergebnis liefern, habe ich den Code entsprechend angepasst:

import datetime
import time

timestamp = '1387965457'  # der Original-Timestamp

def test1():
    datetimetuple = datetime.datetime.fromtimestamp(int(timestamp))  # Umwandeln in ein datetime-Objekt
    datetime_fullhour = datetime.datetime(  # Erstellen eines neuen datetime-Objekts, in welchem Minuten und Sekunden genullt sind
        datetimetuple.year,
        datetimetuple.month,
        datetimetuple.day,
        datetimetuple.hour)
    timestamp_fullhour = int(time.mktime(datetime_fullhour.timetuple()))  # Umwandeln des neuen Objekts in einen Unix-Timestamp
    return timestamp_fullhour

def test2():
    fullhour = int(timestamp) - (int(timestamp) % (60*60))
    return fullhour

print test1()
print test2()

Wie sich herausstellte, liefern beide Funktionen das gleiche Ergebnis. In der Diskussion kam jedoch noch die Vermutung auf, dass der Code von Alex ggf. schneller sein könnte, da weniger Module und auch weniger Objekt-Instanzen benötigt werden. Um dies zu prüfen, habe ich den Quelltext umgeschrieben und das Python-Module ‘timeit’ verwendet. Damit sah der Code wie folgt aus:

import datetime
import time
import timeit

timestamp = '1387965457'  # der Original-Timestamp

def test1():
    datetimetuple = datetime.datetime.fromtimestamp(int(timestamp))  # Umwandeln in ein datetime-Objekt
    datetime_fullhour = datetime.datetime(  # Erstellen eines neuen datetime-Objekts, in welchem Minuten und Sekunden genullt sind
        datetimetuple.year,
        datetimetuple.month,
        datetimetuple.day,
        datetimetuple.hour)
    timestamp_fullhour = int(time.mktime(datetime_fullhour.timetuple()))  # Umwandeln des neuen Objekts in einen Unix-Timestamp
    return timestamp_fullhour

def test2():
    fullhour = int(timestamp) - (int(timestamp) % (60*60))
    return fullhour

print timeit.timeit(test1, number=10000)
print timeit.timeit(test2, number=10000)

Das Ergebnis zeigte, dass mein ursprünglicher Code fast 4x langsamer war, als der von Alex. Um noch einen drauf zusetzen, habe ich den timestamp nicht als string sondern als integer deklariert und die Umwandlung von string zu integer (mittels int()) entfernt. Das Ergebnis überraschte! Durch diese, doch sehr kleine, Änderung unterschied sich die Performance beider Funktionen um Faktor 20.

Weitere Erklärungen und die Ergebnisse des Benchmarkings, könnt Ihr im folgenden Video sehen:

Über weitere Empfehlungen, gerade in Bezug auf timeit, freue ich mich!

Torsten Feld :

This website uses cookies.