Was ist schneller? getter oder dictionary-Abfrage?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

ich verwende in meinem Programm ein Dictionary, in dem ich alle nötigen Daten für eine Kalenderansicht ablege. Das dict hat folgende Struktur:

coords{view_key:{size:(w,h)}, {days:{day_key:{day_x:x}, {day_y:y}, {day_h:h}...}

Und das ist nur der Anfang dieser total hirnrissigen Struktur. Den Rest erspar' ich Euch... :-) Jedenfalls bin ich gerade dabei, den Bereich der Kalenderansicht neu zu strukturieren und möchte im Zuge dessen auch das genannte dict vereinfachen oder die Daten in separaten Klassen unterbringen. Wenn ich mich für die Klassen-Variante entscheide (die ich auch favorisiere) bleibt die Frage, ob dann der Zugriff auf die Daten über diverse get-Methoden genauso schnell erfolgt wie die Abfrage eines Dictionaries. Ich müsste, um z. B. auf einen Tag zuzugreifen, von der View()-Klasse aus eine get-Methode in der Tag()-Klasse aufrufen, die wiederum diverse Werte zurück an die View()-Klasse gibt.

Hat da jemand 'ne Ahnung?

Gruß
mutetella
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Der Dictionary-Zugriff wird schneller sein, aber wenn du dir darüber Sorgen machst, solltest du vielleicht kein Python verwenden.
BlackJack

@mutetella: Vor allem was erwartest Du denn da an Datenmengen bzw. Anzahl von Zugriffen das irgendjemand den Unterschied auch nur ansatzweise wahrnimmt!?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

BlackJack hat geschrieben:Vor allem was erwartest Du denn da an Datenmengen bzw. Anzahl von Zugriffen
Wenn ich eine Monatsansicht mit 10 Terminen/Tag habe, dann sind das 300 Termine... Demnach also 30 getter für die Tage und 300 getter für die Termine. Ist da ein Unterschied zu merken?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

mutetella hat geschrieben:Wenn ich eine Monatsansicht mit 10 Terminen/Tag habe, dann sind das 300 Termine... Demnach also 30 getter für die Tage und 300 getter für die Termine. Ist da ein Unterschied zu merken?
Eher nicht. Kannst es ja mal Benchmarken.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Leonidas hat geschrieben:Kannst es ja mal Benchmarken.
Wenn Du mir jetzt noch sagst, wie ich das mache... :oops:
lunar

In der Standardbibliothek gibt es Module sowohl für Zeitmessung als auch für Profiling, Du musst nur die Dokumentation lesen :)
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

lunar hat geschrieben:Du musst nur die Dokumentation lesen
Schon klar... time(), timeit() and so on... Ich dachte halt, vielleicht gibt es noch was ganz speziell raffiniertes... :-)

Wenn ich soweit bin, werd' ich Euch die Ergebnisse posten. Vielleicht interessierts ja jemanden...

Gruß
mutetella
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Verwende das, was mehr Sinn macht. Wenn du das Gefühl hast, OO ist an der Stelle geeigneter, dann verwende es. Das ist viel wichtiger.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

mkesper hat geschrieben:Verwende das, was mehr Sinn macht. Wenn du das Gefühl hast, OO ist an der Stelle geeigneter, dann verwende es. Das ist viel wichtiger.
Ich möchte Dir nicht ganz Unrecht geben, allerdings hoffe ich, dass eines Tages nicht nur ich, sondern auch andere meinen Kalender verwenden. Und denen ist es ziemlich egal, welches Gefühl ich beim Programmieren hatte. Die erwarten ein Programm, das sich für sie gut anfühlt. Und da spielt Performance eine gewichtige Rolle. Auch wenn das oft nicht wirklich messbar ist, die so oft zitierte 'gefühlte' Geschwindigkeit lässt sich nicht ignorieren.

Wie versprochen (und das wird auch nicht gebrochen... :-) ) schicke ich hier noch meine kleine Testroutine. Ich hoffe, ich habe keinen elementaren Fehler begangen. Wenn doch, dann wär' ich für einen 'Schrei der Entrüstung' wie immer sehr dankbar:

Code: Alles auswählen

import time

class test():
    def __init__(self, count):
        self.dict = {}
        for i in range(count):
            self.dict[i] = i

    def get(self, i):
        return self.dict[i]

def start(loop=100, count=10000):
    instanz = test(count)
    get = ins = dic = lis = 0
    for i in range(loop):
        dict = {}
        list = []
#Get-Abfrage    
        t = time.time()
        for i in range(count):
            dummy = instanz.get(i)
        get += time.time() - t
#Instanz-Abfrage
        t = time.time()
        for i in range(count):
            dummy = instanz.dict[i]
        ins += time.time() - t
#Dictionary-Abfrage
        for i in range(count):
            list.append(i)
            dict[i] = i
        t = time.time()
        for i in range(count):
            dummy = dict[i]
        dic += time.time() - t
#List-Abfrage
        t = time.time()
        for i in range(count):
            dummy = list[i]
        lis += time.time() - t
#Auswertung
    champ = [(get/loop,'(Get)'), (ins/loop,'(Instanz)'), 
        (dic/loop,'(Dictionary)'), (lis/loop,'(Liste)')]
    champ.sort()
    print('%i x %i Abfragen ergeben durchschnittlich:'
        % (loop,count))
    for i in champ:
        print(str(i[0])+' '+i[1])

Nun ja, zumindest auf meinem nicht wirklich flotten Samsung X20 sind Get-Methoden ab einer bestimmten Menge nicht mehr ganz so dolle...

Gruß
mutetella
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ist nicht gerade verwunderlich, da die Basiskosten (=Dictionary-Zugriff) gleich bleiben und Funktionsaufrufe in Python relativ teuer sind.

Die Frage ist natuerlich, warum du denn `getter` haben willst, wenn du schon mit einem normalen Dictionary-Zugriff zufrieden bist und ich denke darauf wollte mkesper hinaus.
BlackJack

@mutetella: Das ist ein ziemlich blödsinniges Argument. Es ist hier auf jeden Fall wichtiger wie Du Dich beim Schreiben, Lesen, und Warten des Programms fühlst. Denn den Anwendern ist es ja auch wichtig, dass Du Fehler beseitigst und das Programm weiterentwickelst. Und das machst Du nur wenn Du das auch willst und kannst; also nicht wenn Dein Code zwar schnell ist, Du aber nicht mehr durchsteigst, und wenn Du nicht jedesmal mit Grauen an den Quelltext denkst wenn Du ihn ändern musst.

Und einfach nur die Geschwindigkeit messen und die Zahlen vergleichen ist auch kein Massstab. Der "schönere" Quelltext kann 500 mal langsamer sein und man kann und sollte ihn trotzdem verwenden solange auch 500 mal langsamer noch schnell genug ist. 300 Objekte sind keine grosse Zahl. Solange man keine wirklich ungünstigen Algorithmen mit quadratischen Laufzeiten oder schlimmer darauf loslässt, merkt das kein Anwender ob da nun ein Indexzugriff, ein Attributzugriff, oder gar ein Methodenaufruf stattfindet. Bei solchen Sachen sollte man *immer* erst auf die Les- und Wartbarkeit des Quelltextes achten und erst wenn *nachweislich* etwas zu langsam ist, solche Mikrooptimierungen vornehmen -- nachdem andere Alternativen ausgeschöpft sind. Sonst könntest Du auch gleich präventiv in Assembler programmieren.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ok, ihr habt Recht! Ich bin über's Ziel hinausgeschossen. Gerade weil ich mich mit der Struktur nicht mehr wohlfühle, habe ich begonnen, mein view-Modul umzubauen. Es ist zwar echt schnell, aber jede Änderung oder jedes Hinzufügen war der absolute Horror, allein das Dictionary, das ich darin verwende, muss ich mir jedesmal wieder von neuem selbst erklären... :P
Jedenfalls habe ich einfach die Befürchtung, dass nach dem Aufräumen zwar alles schön ordentlich ist, aber eben nicht mehr so schnell. Nun ja... ich und meine Befürchtungen stehen mir da mal wieder im Weg! :?
Danke, dass ihr mir den Kopf zurechtgerückt habt! :roll:

Gruß
mutetella


P.S. Trotzdem: Es war interessant und ich hab' wieder a bisl dazugelernt...
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

mutetella hat geschrieben:

Code: Alles auswählen

        t = time.time()
        for i in range(count):
            dummy = instanz.get(i)
        get += time.time() - t
Genau dafür gibt es das timeit Modul denn:
http://docs.python.org/library/timeit.html hat geschrieben:The default timer function is platform dependent. On Windows, time.clock() has microsecond granularity but time.time()‘s granularity is 1/60th of a second; on Unix, time.clock() has 1/100th of a second granularity and time.time() is much more precise. On either platform, the default timer functions measure wall clock time, not the CPU time. This means that other processes running on the same computer may interfere with the timing. The best thing to do when accurate timing is necessary is to repeat the timing a few times and use the best time. The -r option is good for this; the default of 3 repetitions is probably enough in most cases. On Unix, you can use time.clock() to measure CPU time.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Sr4l hat geschrieben:Genau dafür gibt es das timeit Modul
Das ist mir bekannt, allerdings finde ich timeit() zur Zeitmessung irgendwie sehr mühsam in der Anwendung. time() ist da viel einfacher einzusetzen und soweit ich das mit ein paar kleinen Versuchen sehe sind die Unterschiede nicht so gravierend...
Auf der Idle-Ebene ist das sicher 'ne tolle Sache, aber innerhalb eines Programms echt komisch. Schon der Umstand, dass ich timeit() dann quasi sich selbst wieder importieren lasse, damit die Namensräume bekannt sind, finde ich irgendwie gruselig... :?

Meine Meinung.

Gruß
mutetella
lunar

@mutuella: Das habe ich jetzt nicht verstanden. Was bedeutet "innerhalb" eines Programms? Wieso musst Du das "wieder selbst importieren"?

Kann es sein, dass Du nicht verstanden hast, wie timeit anzuwenden ist?
BlackJack

Innerhalb eines Programms ist IMHO Profiling sowieso die bessere Lösung. Da kann man sich dann auch die Zeit auf die einzelnen Funktionen/Aufrufe runterbrechen lassen und weiss dann nicht nur wie lange es gebraucht hat, sondern auch *wo* es wie lange gebraucht hat.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

lunar hat geschrieben:Kann es sein, dass Du nicht verstanden hast, wie timeit anzuwenden ist?
Das kann nicht sein. Das ist so... :D
Wenn ich z. B. innerhalb von 'test.py' die Funktion

Code: Alles auswählen

def hallo(anzahl):
    for i in range(anzahl):
        print('Voelliger Quatsch')
messen möchte, dann muss ich doch timeit() folgendermaßen verwenden:

Code: Alles auswählen

import timeit

def hallo(anzahl):
    for i in range(anzahl):
        print('Voelliger Quatsch')

timer = timeit.Timer('hallo(100)', 'import test')
print(timer.timeit(number=1)
Bei mir verursacht das immer nur ein 'global name hallo is not defined', ich könnte schreien....

Auch der Beispielcode aus der timeit()-Doku funktioniert nicht:

Code: Alles auswählen

def test():
    "Stupid test function"
    L = []
    for i in range(100):
        L.append(i)

if __name__=='__main__':
    from timeit import Timer
    t = Timer("test()", "from __main__ import test")
    print t.timeit()
Gruß
mutetella
Benutzeravatar
jbs
User
Beiträge: 953
Registriert: Mittwoch 24. Juni 2009, 13:13
Wohnort: Postdam

Was heißt denn funktioniert nicht? Bei mir geht der gezeigte code aus der doku.
[url=http://wiki.python-forum.de/PEP%208%20%28%C3%9Cbersetzung%29]PEP 8[/url] - Quak!
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ok, ich geh' Schafe hüten....

Zeile 7 muss natürlich lauten:

timer = timeit.Timer('hallo(100)', 'from test import hallo')

Oder dann eben 'from __main__' oder woher auch immer... :-)

Voll peinlich.... :oops:

Gruß
mutetella
Antworten