Optimierung

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.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

albertus hat geschrieben:Was ist schneller das Zeilenweise auslesen einer Datei mit nachfolgenden rstrip(), oder das einlesen einer Datei in einem Rutsch mit nachfolgenden split("\n")? Denn gefragt wird hier nach der Geschwindigkeit und nicht nach der Speicher schonendsten Möglichkeit.
Da Speicherzugriff relativ teuer ist, würde ich das nicht unbedingt als orthogonal ansehen. Zugegeben Python ist nicht direkt die richtige Sprache, wenn man sich ueber Cache Misses Gedanken macht, aber deshalb muss man sich auch nicht wie eine Wildsau beim Speicher auffuehren.
albertus
User
Beiträge: 52
Registriert: Mittwoch 7. Juli 2010, 14:48

BlackJack hat geschrieben:@albertus: Kein Ahnung was schneller ist. Ich weiss aber dass Deine Methode deutlich umständlicher ausgedrückt ist als ein einfaches ``list(datei)`` oder ``datei.readlines()``. In wie weit dabei wirklich zeilenweise eingelesen wird, ist dann übrigens eine Implementierungsfrage. Ohne zu *wissen* das es *deutlich* schneller ist, sollte man das IMHO nicht so umständlich schreiben.
Dann probieren wir es doch einfach mal aus:

Code: Alles auswählen

#!/usr/bin/python

import profile

def start():
    f = open("/home/albert/foo.txt", "w")
    abc = "abcdefghijklmnopqrstuvwxyz"
    for i1 in abc:
        for i2 in abc:
            for i3 in abc:
                for i4 in abc:
                        f.write(i1+i2+i3+i4+"\n")

    f.close()

def test1():
    datei = open("/home/albert/foo.txt")
    a = set(s.rstrip() for s in datei)

def test2():
    string = open("/home/albert/foo.txt").read()
    a = set(string.splitlines())

#start()

profile.run("test1()")
profile.run("test2()")
Ergebnis bei mir:

Für Test 1
913958 function calls in 7.942 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 :0(open)
456976 1.903 0.000 1.903 0.000 :0(rstrip)
1 0.001 0.001 0.001 0.001 :0(setprofile)
1 0.051 0.051 7.941 7.941 <string>:1(<module>)
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 7.942 7.942 profile:0(test1())
1 2.059 2.059 7.890 7.890 rutsch.py:18(test1)
456977 3.928 0.000 5.831 0.000 rutsch.py:20(<genexpr>)


Für Test 2
7 function calls in 0.292 CPU seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.000 0.000 :0(open)
1 0.004 0.004 0.004 0.004 :0(read)
1 0.001 0.001 0.001 0.001 :0(setprofile)
1 0.060 0.060 0.060 0.060 :0(splitlines)
1 0.051 0.051 0.291 0.291 <string>:1(<module>)
0 0.000 0.000 profile:0(profiler)
1 0.000 0.000 0.292 0.292 profile:0(test2())
1 0.176 0.176 0.240 0.240 rutsch.py:23(test2)

Ich denke die Zahlen sind Aussagefähig genug. Aber ich gebe euch allen Recht meine Methode ist sehr Speicher intensiv. Ich selber würde sie auch nur anwenden wenn zwei Bedingungen erfühlt sind:
1. Beim Start des Programms um Wartezeiten zu vermeiden
2. Wenn ich die Datei nur einmal einlesen muss

Eines möchte ich noch Anmerken: Die Liste die ich zusätzlich erzeuge hat nur für eine kurze Zeit bestand.

Mit freundlichen Grüßen

Albertus
Mit freundlichen Grüßen

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

Dir ist klar, dass `test1` mehr Arbeit leistet als `test2`? Ohne den `rstrip`-Aufruf und damit 2 aequivalenten Funktionen kommt man auf einen vernachlaessigbaren Unterschied (mit `timeit`, da profile nicht will):

Code: Alles auswählen

In [8]: timeit.timeit(test1, number=1)                                                              
Out[8]: 0.58121109008789062

In [9]: timeit.timeit(test2, number=1)                                                              
Out[9]: 0.36374115943908691
albertus
User
Beiträge: 52
Registriert: Mittwoch 7. Juli 2010, 14:48

cofi hat geschrieben:Dir ist klar, dass `test1` mehr Arbeit leistet als `test2`? Ohne den `rstrip`-Aufruf und damit 2 aequivalenten Funktionen kommt man auf einen vernachlaessigbaren Unterschied (mit `timeit`, da profile nicht will):

Code: Alles auswählen

In [8]: timeit.timeit(test1, number=1)                                                              
Out[8]: 0.58121109008789062

In [9]: timeit.timeit(test2, number=1)                                                              
Out[9]: 0.36374115943908691

Ist mir klar aber in der Praxis braucht Dein Vorschlag rstrip für jede Zeile mein Vorschlag nicht. Deshalb ist der deinige langsam der meinige nicht. Aber wie gesagt es kommt drauf an ob man beim start des Programms das set einmal erzeugen muss oder nicht. Braucht man mehrmals ein neues Set sieht die Sache anders aus.

Mit freundlichen Grüßen

Albert
Mit freundlichen Grüßen

Albertus
Antworten