Ich muss eine Zeilenanzahl einer großen Datei (Hunderttausende von Zeilen) in Python erhalten. Was ist der effizienteste Weg sowohl in Bezug auf das Gedächtnis als auch in Bezug auf die Zeit?
Im Moment mache ich:
def file_len(fname):
with open(fname) as f:
for i, l in enumerate(f):
pass
return i + 1
ist es möglich, es besser zu machen?
python
text-files
line-count
SilentGhost
quelle
quelle
enumerate(f, 1)
und deni + 1
?Antworten:
Besser geht es nicht.
Schließlich muss jede Lösung die gesamte Datei lesen, herausfinden, wie viele
\n
Sie haben, und dieses Ergebnis zurückgeben.Haben Sie eine bessere Möglichkeit, dies zu tun, ohne die gesamte Datei zu lesen? Nicht sicher ... Die beste Lösung ist immer E / A-gebunden. Das Beste, was Sie tun können, ist sicherzustellen, dass Sie keinen unnötigen Speicher verwenden, aber es sieht so aus, als hätten Sie diesen abgedeckt.
quelle
Eine Zeile, wahrscheinlich ziemlich schnell:
quelle
Ich glaube, dass eine Speicherzuordnungsdatei die schnellste Lösung sein wird. Ich habe vier Funktionen ausprobiert: die vom OP (
opcount
) gepostete Funktion ; eine einfache Iteration über die Zeilen in der Datei (simplecount
); readline mit einem speicherabgebildeten Feld (mmap) (mapcount
); und die von Mykola Kharechko (bufcount
) angebotene Pufferleselösung .Ich habe jede Funktion fünf Mal ausgeführt und die durchschnittliche Laufzeit für eine Textdatei mit 1,2 Millionen Zeilen berechnet.
Windows XP, Python 2.5, 2 GB RAM, 2 GHz AMD-Prozessor
Hier sind meine Ergebnisse:
Edit : Zahlen für Python 2.6:
Daher scheint die Pufferlesestrategie für Windows / Python 2.6 die schnellste zu sein
Hier ist der Code:
quelle
wccount()
der schnellste ist gist.github.com/0ac760859e614cd03652Ich musste dies auf eine ähnliche Frage posten, bis mein Reputationswert ein wenig sprang (danke an jeden, der mich gestoßen hat!).
Alle diese Lösungen ignorieren eine Möglichkeit, diesen Lauf erheblich zu beschleunigen, nämlich die Verwendung der ungepufferten (Roh-) Schnittstelle, die Verwendung von Bytearrays und die eigene Pufferung. (Dies gilt nur in Python 3. In Python 2 wird die Rohschnittstelle möglicherweise standardmäßig verwendet oder nicht, in Python 3 wird jedoch standardmäßig Unicode verwendet.)
Unter Verwendung einer modifizierten Version des Timing-Tools ist der folgende Code meiner Meinung nach schneller (und geringfügig pythonischer) als jede der angebotenen Lösungen:
Mit einer separaten Generatorfunktion wird ein Smidge schneller ausgeführt:
Dies kann vollständig mit Generatorausdrücken inline unter Verwendung von itertools durchgeführt werden, aber es sieht ziemlich seltsam aus:
Hier sind meine Timings:
quelle
wccount
in dieser Tabelle für das Subprozess-Shell-wc
Tool?rawincount
Lösung weniger seltsam aussehen lassen, indem Siebufgen = iter(partial(f.raw.read, 1024*1024), b'')
statt kombinierentakewhile
undrepeat
.Sie können einen Unterprozess ausführen und ausführen
wc -l filename
quelle
Hier ist ein Python-Programm, mit dem die Multiprozessor-Bibliothek verwendet wird, um die Zeilenzählung auf Maschinen / Kerne zu verteilen. Mein Test verbessert das Zählen einer 20-Millionen-Zeilendatei von 26 Sekunden auf 7 Sekunden unter Verwendung eines 8-Kern-Windows 64-Servers. Hinweis: Wenn Sie keine Speicherzuordnung verwenden, werden die Dinge viel langsamer.
quelle
Eine einzeilige Bash-Lösung ähnlich dieser Antwort unter Verwendung der modernen
subprocess.check_output
Funktion:quelle
wc -l
~ 5 Sekunden dauert.shell=True
ist schlecht für die Sicherheit, es ist besser, es zu vermeiden.Ich würde Pythons Dateiobjektmethode
readlines
wie folgt verwenden:Dies öffnet die Datei, erstellt eine Liste von Zeilen in der Datei, zählt die Länge der Liste, speichert diese in einer Variablen und schließt die Datei erneut.
quelle
xreadlines
seit 2.3 veraltet, da nur ein Iterator zurückgegeben wird.for line in file
ist der angegebene Ersatz. Siehe: docs.python.org/2/library/stdtypes.html#file.xreadlinesquelle
Folgendes benutze ich, scheint ziemlich sauber zu sein:
UPDATE: Dies ist geringfügig schneller als die Verwendung von reinem Python, jedoch auf Kosten der Speichernutzung. Der Unterprozess gibt einen neuen Prozess mit dem gleichen Speicherbedarf wie der übergeordnete Prozess aus, während er Ihren Befehl ausführt.
quelle
:-)
Dies ist das schnellste, was ich mit reinem Python gefunden habe. Sie können beliebig viel Speicher verwenden, indem Sie den Puffer einstellen, obwohl 2 ** 16 ein Sweet Spot auf meinem Computer zu sein scheint.
Ich habe die Antwort hier gefunden. Warum ist das Lesen von Zeilen aus stdin in C ++ viel langsamer als in Python? und optimierte es nur ein kleines bisschen. Es ist eine sehr gute Lektüre, um zu verstehen, wie man Zeilen schnell zählt, obwohl
wc -l
es immer noch etwa 75% schneller ist als alles andere.quelle
Ich habe mit dieser Version eine kleine Verbesserung (4-8%) erzielt, bei der ein konstanter Puffer wiederverwendet wird, um Speicher- oder GC-Overhead zu vermeiden:
Sie können mit der Puffergröße herumspielen und vielleicht eine kleine Verbesserung feststellen.
quelle
Kyles Antwort
ist wohl am besten, eine alternative dafür ist
Hier ist der Vergleich der Leistung von beiden
quelle
Einzeilige Lösung:
Mein Ausschnitt:
quelle
os.system()
Variablen sowieso nicht speichern und nachbearbeiten.Um die oben genannten Methoden zu vervollständigen, habe ich eine Variante mit dem Dateieingabemodul ausprobiert:
Und eine 60-mil-Zeilendatei an alle oben genannten Methoden übergeben:
Es ist eine kleine Überraschung für mich, dass der Dateieingang so schlecht ist und weitaus schlechter skaliert als alle anderen Methoden ...
quelle
Für mich wird diese Variante die schnellste sein:
Gründe: Pufferung schneller als zeilenweises Lesen und
string.count
auch sehr schnellquelle
Dieser Code ist kürzer und klarer. Es ist wahrscheinlich der beste Weg:
quelle
Ich habe den Pufferfall folgendermaßen geändert:
Jetzt werden auch leere Dateien und die letzte Zeile (ohne \ n) gezählt.
quelle
Was ist damit?
quelle
count = max(enumerate(open(filename)))[0]
quelle
enumerate()
ist Startzählungquelle
quelle
Wenn man die Zeilenanzahl in Python unter Linux billig erhalten möchte, empfehle ich diese Methode:
Dateipfad kann sowohl ein abstrakter Dateipfad als auch ein relativer Pfad sein. Hoffe das kann helfen.
quelle
Wie wäre es damit?
quelle
Wie wäre es mit diesem Einzeiler:
Mit dieser Methode dauert es 0,003 Sekunden, um die Zeit in einer 3900-Zeilendatei zu messen
quelle
quelle
Einfache Methode:
1)
2)
3)
quelle
Das Ergebnis des Öffnens einer Datei ist ein Iterator, der in eine Sequenz konvertiert werden kann, die eine Länge hat:
Dies ist prägnanter als Ihre explizite Schleife und vermeidet das
enumerate
.quelle
Sie können das
os.path
Modul folgendermaßen verwenden:, wo
Filename
ist der absolute Pfad der Datei.quelle
os.path
?Wenn die Datei in den Speicher passt, dann
quelle