2016-04-23 11 views
1

Ich möchte den Effekt der Verarbeitung eines Streams als Filter (das heißt, ein wenig zu bekommen, zu verarbeiten, spülen), gegen schlürfen (das heißt, alle Informationen erhalten, dann verarbeiten) vergleichen.Eine Datei in Python lesen: schlürfen oder filtern?

Wenn ich jedoch die beiden Codes unten ausführe, bekomme ich vergleichbare Ergebnisse. Ich hatte erwartet, in der Slurp-Version ein viel schlechteres Ergebnis zu erzielen.

Sind die unten aufgeführten Code-Schnipsel anders als oben beschrieben? Wenn sie gleichwertig sind, wie könnte ich einen von ihnen anpassen, um die Filter/Schluck-Differenz zu testen?

I testete die Skripte mit:

jot 100000000 | time python3 dont_slurp.py > /dev/null 
jot 100000000 | time python3 slurp.py > /dev/null 

Jot erzeugt Zahlen von 1 bis x. Die Code-Snippets nummerieren nur die Zeilen.

Filter:

import sys 
lineno = 0 
for line in sys.stdin: 
    lineno += 1 
    print("{:>6} {}".format(lineno, line[:-1])) 

Slurp:

import sys 

f = sys.stdin 
lineno = 0 

for line in f: 
    lineno += 1 
    print('{:>6} {}'.format(lineno, line[:-1])) 
+2

Die "Slurp" -Version tut nicht, was Sie denken, dass es tut. Beide Versionen lesen jeweils eine Zeile. Um alle Zeilen auf einmal zu lesen, würden Sie 'for line in f.readlines()' machen. –

Antwort

0

Zu allererst Ihre Codebeispiele tun nicht das, was Sie denken. Alle f = sys.stdin ist f auf das gleiche Datei-Handle gesetzt. Die Zeilen for line in f: und for line in sys.stdin: sind funktional identisch.

Was Sie wollen, ist dies:

import sys 

lineno = 0 

for line in sys.stdin.readlines(): 
     lineno += 1 
     print('{:>6} {}'.format(lineno, line[:-1])) 

readlines() gibt eine Liste, ein Element pro Zeile in der Datei. Ich glaube, es ist nicht ein Generator, so erhalten Sie die vollständige Liste. Das Dateihandle selbst fungiert als Generator und gibt Ihnen jeweils eine Zeile.

Sie sollten Leistungsunterschiede mit readline() sehen.

Allerdings die Antwort auf "was ist besser?" ist "es kommt darauf an". Wenn Sie zeilenweise lesen, führen Sie einen Systemaufruf aus, der wiederum dazu führt, dass das Betriebssystem Dateiinhalte in Blöcken von der Festplatte liest. Diese Blöcke sind wahrscheinlich größer als die Größe der Durchschnittslinie, und der Block wird wahrscheinlich zwischengespeichert. Das bedeutet, dass Sie manchmal auf die Festplatte klopfen und viel Zeit in Anspruch nehmen.

Wenn Sie alle auf einmal lesen, laden Sie jedes Byte aus der Datei gleichzeitig in den Speicher. Wenn Sie über genügend freien Speicher verfügen, um alle Dateiinhalte zu speichern, dauert dies genauso viel Zeit wie bei der zeilenweisen Version. In beiden Fällen ist es im Prinzip nur die Zeit, die ganze Datei sequentiell mit ein wenig Overhead zu lesen.

Der Unterschied besteht darin, dass Sie nicht genügend freien Speicher haben, um die gesamte Datei zu speichern. In diesem Fall lesen Sie die gesamte Datei, aber Teile davon werden vom virtuellen Speichersystem wieder auf die Festplatte ausgelagert. Sie müssen dann wieder eingezogen werden, wenn Sie auf diese bestimmte Zeile zugreifen.

Wie viel Zeit verloren ist, hängt davon ab, wie viel Speicher belegt ist, wie viel andere Aktivitäten auf Ihrem System laufen usw., so dass es im Allgemeinen nicht quantifiziert werden kann.

Dies ist ein Fall, in dem Sie sich ehrlich nicht darum kümmern sollten, bis es ein Problem gibt. Machen Sie das, was im Code natürlicher ist, und sorgen Sie sich nur um die Leistung, wenn Ihr Programm zu langsam ist.

+0

Ich denke, ein weiterer Punkt, auf den es sich zu beziehen lohnt, ist, dass Sie bei der Filterung möglicherweise E/A- und CPU-Arbeiten parallel durchführen können. –