2015-04-20 18 views
6

Wie es ist, gibt es viele Ansätze zum Lesen einer Datei in eine Zeichenfolge.Warum liest ifstream :: viel schneller als Iteratoren?

Mit ifstream lesen :::

std::ifstream in {"./filename.txt"}; 
std::string contents; 
in.seekg(0, in.end); 
contents.resize(in.tellg()); 
in.seekg(0, in.beg); 
in.read(&contents[0], contents.size()); 

Mit std :: copy_n: direkt in einen String und mit steambuf_iterators zusammen mit std :: copy_n zu lesen Zwei gewöhnlichsten verwenden ifstream :: read

std::ifstream in {"./filename.txt"}; 
std::string contents; 
in.seekg(0, in.end); 
contents.resize(in.tellg()); 
in.seekg(0, in.beg); 
std::copy_n(std::streambuf_iterator<char>(in), 
      contents.size(), 
      contents.begin(); 

Viele Benchmarks zeigen, dass der erste Ansatz ist viel schneller als die zweite (in meinem Rechner g ++ verwenden - 4.9 ist etwa 10-mal schneller mit beiden -O2 und O3 Flaggen) und ich habe mich gefragt, was sein kann, der Grund für diesen Unterschied in der Leistung.

+1

Ich vermute, der Iterator liest ein Zeichen nach dem anderen. Das würde den Unterschied erklären. –

+0

@RSahu: Genauer gesagt verwendet der Iterator für jedes Byte 1+ virtuelle Aufrufe, während "read" 1-2 virtuelle Aufrufe pro Puffer sind. –

+1

Side Kommentar: Sie können auch die Zeichenfolge an Ort und Stelle wie 'std :: string contents (std :: streambuf_iterator (in), {});', keine Notwendigkeit für 'copy_n' und bekommen die Größe der Datei. Aber wahrscheinlich wird es keinen großen Unterschied in Bezug auf die Geschwindigkeit machen. – vsoftco

Antwort

2

read ist ein einzelnes Iostream-Setup (Teil jeder Iostream-Operation) und ein einzelner Aufruf des Betriebssystems, der direkt in den von Ihnen bereitgestellten Puffer einliest.

Der Iterator arbeitet durch wiederholtes Extrahieren einer einzelnen char mit operator>>. Aufgrund der Puffergröße kann dies mehr OS-Aufrufe bedeuten, aber was noch wichtiger ist, bedeutet auch, dass der Iostream-Sentry wiederholt eingerichtet und heruntergefahren wird, was eine Mutex-Sperre bedeuten kann und normalerweise eine Menge anderer Dinge bedeutet. Außerdem ist operator>> eine formatierte Operation, während read unformatiert ist, was zusätzlichen Setup-Overhead bei jeder Operation bedeutet.

Bearbeiten: Müde Augen sah istream_iterator statt istreambuf_iterator. Natürlich macht istreambuf_iterator keine formatierten Eingaben. Es ruft sbumpc oder etwas ähnliches auf dem streambuf an. Immer noch viele Anrufe und die Verwendung des Puffers, der wahrscheinlich kleiner als die gesamte Datei ist.

+1

"Der Iterator arbeitet durch wiederholtes Extrahieren eines einzelnen Zeichens mit' Operator >> '" - irgendeine Referenz dafür? Tatsächlich hat 'operator >>' eine formatierte Eingabe, während 'istreambuf_iterator' eine * unformatierte * Eingabe hat, also denke ich, dass das unwahrscheinlich ist. (EDIT: Nach [cppreference.com] (http://en.cppreference.com/w/cpp/iterator/istrambuf_iterator/operator*) ist diese Antwort falsch.) –

+0

Das ist eine Art der Definition von was für ein streambuf_iterator ist, Konrad. Bei jeder Verwendung extrahiert es ein einzelnes Zeichen aus dem entsprechenden Stream-Puffer. – Peter

+0

@KonradRudolph Sie haben Recht. Ich habe es als iStream_iterator falsch gelesen. –

Verwandte Themen