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
Was ist schneller? getter oder dictionary-Abfrage?
@mutetella: Vor allem was erwartest Du denn da an Datenmengen bzw. Anzahl von Zugriffen das irgendjemand den Unterschied auch nur ansatzweise wahrnimmt!?
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?BlackJack hat geschrieben:Vor allem was erwartest Du denn da an Datenmengen bzw. Anzahl von Zugriffen
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Eher nicht. Kannst es ja mal Benchmarken.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?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Wenn Du mir jetzt noch sagst, wie ich das mache...Leonidas hat geschrieben:Kannst es ja mal Benchmarken.
In der Standardbibliothek gibt es Module sowohl für Zeitmessung als auch für Profiling, Du musst nur die Dokumentation lesen
Schon klar... time(), timeit() and so on... Ich dachte halt, vielleicht gibt es noch was ganz speziell raffiniertes...lunar hat geschrieben:Du musst nur die Dokumentation lesen
Wenn ich soweit bin, werd' ich Euch die Ergebnisse posten. Vielleicht interessierts ja jemanden...
Gruß
mutetella
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.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.
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
- 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.
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.
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
@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.
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.
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...
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!
Gruß
mutetella
P.S. Trotzdem: Es war interessant und ich hab' wieder a bisl dazugelernt...
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!
Gruß
mutetella
P.S. Trotzdem: Es war interessant und ich hab' wieder a bisl dazugelernt...
- Sr4l
- User
- Beiträge: 1091
- Registriert: Donnerstag 28. Dezember 2006, 20:02
- Wohnort: Kassel
- Kontaktdaten:
Genau dafür gibt es das timeit Modul denn:mutetella hat geschrieben:Code: Alles auswählen
t = time.time() for i in range(count): dummy = instanz.get(i) get += time.time() - t
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.
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...Sr4l hat geschrieben:Genau dafür gibt es das timeit Modul
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
@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?
Kann es sein, dass Du nicht verstanden hast, wie timeit anzuwenden ist?
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.
Das kann nicht sein. Das ist so...lunar hat geschrieben:Kann es sein, dass Du nicht verstanden hast, wie timeit anzuwenden ist?
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')
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)
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()
mutetella
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]
[url=http://tutorial.pocoo.org/index.html]Tutorial in Deutsch[/url]
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....
Gruß
mutetella
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....
Gruß
mutetella