getline beim Lesen einer Datei vs. Lesen der ganzen Datei und dann Teilen basierend auf Newline-Zeichen

8

Ich möchte jetzt jede Zeile einer Datei auf einer Festplatte verarbeiten. Ist es besser, eine Datei als Ganzes zu laden und dann auf der Basis eines Zeilenumbruchs (Boost) zu teilen, oder ist es besser, getline() zu verwenden? Meine Frage ist does getline() liest einzelne Zeile beim Aufruf (was zu mehreren Festplattenzugriff) oder liest ganze Datei und gibt Zeile für Zeile?

    
psyche 22.01.2013, 16:24
quelle

6 Antworten

5

getline ruft read() als Systemaufruf irgendwo tief in der C-Bibliothek auf. Wie oft es aufgerufen wird und wie es aufgerufen wird, hängt vom Design der C-Bibliothek ab. Aber höchstwahrscheinlich gibt es keinen deutlichen Unterschied beim Lesen einer Zeile zu einer Zeit gegenüber der gesamten Datei, weil das OS auf der untersten Ebene (mindestens) jeweils einen Plattenblock lesen wird und höchstwahrscheinlich mindestens eine "Seite" "(4KB), wenn nicht mehr.

Außerdem machen Sie fast nichts mit Ihrer Zeichenkette, nachdem Sie sie gelesen haben (zB schreiben Sie etwas wie "grep", also lesen Sie meistens nur die Zeichenkette), es ist unwahrscheinlich, dass der Overhead eine Zeile liest zu einer Zeit ist ein großer Teil der Zeit, die Sie verbringen.

Aber das "Laden der ganzen Datei auf einmal" hat mehrere, unterschiedliche Probleme:

  1. Sie beginnen die Verarbeitung erst, wenn Sie die gesamte Datei gelesen haben.
  2. Sie benötigen genügend Speicher, um die gesamte Datei in den Speicher zu laden - was ist, wenn die Datei einige hundert GB groß ist? Scheitert Ihr Programm dann?

Versuchen Sie nicht, etwas zu optimieren, es sei denn, Sie haben Profiling verwendet, um zu beweisen, dass es ein Teil davon ist, warum Ihr Code langsam läuft. Sie verursachen nur mehr Probleme für sich selbst.

Edit: Also, ich habe ein Programm geschrieben, um das zu messen, da ich denke, dass es ziemlich interessant ist.

Und die Ergebnisse sind definitiv interessant - um den Vergleich fair zu machen, habe ich drei große Dateien von je 1297984192 Bytes erstellt (indem ich alle Quelldateien in ein Verzeichnis mit etwa einem Dutzend verschiedener Quelldateien kopiert habe, dann diese Datei mehrmals in "Multiplizieren" Sie es, bis es dauerte 1,5 Sekunden, um den Test zu laufen, wie lange ich denke, Sie müssen Dinge ausführen, um sicherzustellen, dass das Timing nicht zu anfällig für zufällige "Netzwerk-Paket kam" oder andere äußere Einflüsse nehmen Sie sich Zeit für den Prozess).

Ich entschied mich auch, die System- und Benutzerzeit durch den Prozess zu messen.

%Vor%

Hier sind die drei verschiedenen Funktionen, um die Datei zu lesen (es gibt natürlich einen Code, um Zeit und andere Dinge zu messen, aber um die Größe dieses Beitrags zu reduzieren, habe ich nicht alles gepostet - und ich habe mit der Bestellung herumgespielt) um zu sehen, ob das irgendeinen Unterschied machte, so sind die obigen Ergebnisse nicht in der gleichen Reihenfolge wie die Funktionen hier)

%Vor%     
Mats Petersson 22.01.2013 16:33
quelle
2

Das Betriebssystem liest einen ganzen Datenblock (abhängig davon, wie die Festplatte formatiert ist, normalerweise 4-8k auf einmal) und führt einen Teil der Pufferung für Sie durch. Lassen Sie das OS sich darum kümmern und lesen Sie die Daten so, wie es für Ihr Programm sinnvoll ist.

    
Floris 22.01.2013 16:26
quelle
1

Die fstreams sind vernünftig gepuffert. Die zugrunde liegenden Vorgänge auf der Festplatte durch das Betriebssystem sind vernünftig gepuffert. Die Festplatte selbst hat einen vernünftigen Puffer. Sie werden sicherlich nicht mehr Festplattenzugriffe auslösen, wenn Sie die Datei zeilenweise lesen. Oder Charakter für Charakter.

Es gibt also keinen Grund, die ganze Datei in einen großen Puffer zu laden und an diesem Puffer zu arbeiten, weil bereits in einem Puffer ist. Und oft gibt es auch keinen Grund, eine Zeile gleichzeitig zu puffern. Warum sollte man Speicher reservieren, um etwas in einem String zu puffern, der bereits im ifstream gepuffert ist? Wenn Sie können, arbeiten Sie direkt am Stream und versuchen Sie nicht, alles zweimal oder öfter von einem Puffer zum nächsten zu werfen. Es sei denn, es unterstützt Lesbarkeit und / oder Ihr Profiler sagte Ihnen, dass Disc-Zugriff Ihr Programm erheblich verlangsamt.

    
Arne Mertz 22.01.2013 16:39
quelle
0

Wenn es sich um eine kleine Datei auf der Festplatte handelt, ist es wahrscheinlich effizienter, die gesamte Datei zu lesen und Zeile für Zeile zu analysieren, anstatt Zeile für Zeile zu lesen - das würde viel Festplattenzugriff erfordern.

    
Ray 22.01.2013 16:27
quelle
0

Ich glaube, das C ++ - Idiom wäre, die Datei Zeile für Zeile zu lesen und einen zeilenbasierten Container beim Lesen der Datei zu erstellen. Wahrscheinlich werden die Iostreams ( getline ) ausreichend gepuffert sein, dass Sie keinen signifikanten Unterschied bemerken werden.

Allerdings können Sie bei sehr großen Dateien eine bessere Leistung erzielen, indem Sie größere Teile der Datei (nicht die gesamte Datei auf einmal) lesen und internallieren, wenn Zeilenumbrüche gefunden werden.

Wenn Sie genauer wissen möchten, welche Methode schneller ist und um wie viel, müssen Sie Ihren Code profilieren.

    
Mark B 22.01.2013 16:29
quelle
0

Es ist besser, alle Daten zu holen, wenn sie im Speicher untergebracht werden können, denn jedes Mal, wenn Sie die E / A anfordern, verliert Ihr Programm die Verarbeitung und setzt eine Wartezeit Q.

Wenn jedoch die Dateigröße groß ist, ist es besser, so viele Daten zu einem Zeitpunkt zu lesen, der für die Verarbeitung benötigt wird. Da eine größere Leseoperation viel Zeit in Anspruch nimmt, werden die kleinen gelesen. CPU-Prozess Umschaltzeit ist viel kleiner als die gesamte Datei Lesezeit.

    
Arpit 22.01.2013 16:32
quelle

Tags und Links