13 Stimmen

Was ist der schnellste Weg, um eine 10 GB große Datei von der Festplatte zu lesen?

Wir müssen verschiedene Arten von Nachrichten lesen und zählen / ausführen einige Statistiken über eine 10 GB große Textdatei, z.B. eine FIX Motor Protokoll. Wir verwenden Linux, 32-Bit, 4 CPUs, Intel, programmieren in Perl, aber aber die Sprache ist nicht wirklich wichtig.

Ich habe einige interessante Tipps im Buch von Tim Bray gefunden WideFinder-Projekt . Wir haben jedoch festgestellt, dass die Verwendung von Memory Mapping von Natur aus durch die 32-Bit-Architektur begrenzt ist.

Wir haben versucht, mehrere Prozesse zu verwenden, was zu funktionieren scheint schneller, wenn wir die Datei parallel mit 4 Prozessen auf auf 4 CPUs. Das Hinzufügen von Multi-Threading verlangsamt es, vielleicht wegen der Kosten für die Kontextumschaltung. Wir haben versucht, die Größe des Threadpools zu ändern, aber das ist immer noch langsamer als einfache Multiprozess-Version.

Der Teil der Speicherzuordnung ist nicht sehr stabil, manchmal ist er dauert 80 Sekunden und manchmal 7 Sekunden bei einer 2 GB großen Datei, vielleicht wegen Seitenfehlern oder etwas, das mit der Nutzung des virtuellen Speichers zusammenhängt. Wie auch immer, Mmap kann nicht über 4 GB auf einem 32-Bit-System skalieren. Architektur.

Wir haben Perl's IPC::Mmap y Sys::Mmap . Nachgeschaut auch mit Map-Reduce beschäftigt, aber das Problem ist wirklich I/O gebunden, die Verarbeitung selbst ist ausreichend schnell.

Daher haben wir uns entschlossen, die grundlegende E/A zu optimieren, indem wir die Puffergröße, Typ usw. zu optimieren.

Kennt jemand ein bestehendes Projekt, bei dem diese Problem in irgendeiner Sprache/Plattform effizient gelöst wurde auf einen nützlichen Link hinweisen oder eine Richtung vorschlagen?

2voto

Sinan Ünür Punkte 114993

Analysiert die Datei einmal und liest Zeile für Zeile. Legen Sie die Ergebnisse in einer Tabelle in einer ordentlichen Datenbank ab. Führen Sie so viele Abfragen durch, wie Sie möchten. Füttern Sie die Bestie regelmäßig mit neu eingehenden Daten.

Sie müssen sich darüber im Klaren sein, dass die Bearbeitung einer 10-GB-Datei, ihre Übertragung über das (wenn auch lokale) Netz, die Suche nach komplizierten Lösungen usw. Zeit in Anspruch nehmen.

2voto

Da Sie sagten, Plattform und Sprache spielen keine Rolle...

Wenn Sie eine stabile Leistung wünschen, die so schnell ist, wie es das Quellmedium zulässt, ist die einzige mir bekannte Möglichkeit, dies unter Windows zu erreichen, überlappende nicht-OS-gepufferte ausgerichtete sequenzielle Lesevorgänge. Mit zwei oder drei Puffern kann man wahrscheinlich einige GB/s erreichen, darüber hinaus braucht man irgendwann einen Ringpuffer (ein Schreiber, 1+ Leser), um jegliches Kopieren zu vermeiden. Die genaue Implementierung hängt von den Treibern/APIs ab. Wenn im Thread (sowohl im Kernel- als auch im Usermode), der sich mit der IO befasst, Speicher kopiert wird, wird natürlich umso mehr Zeit damit verschwendet, je größer der zu kopierende Puffer ist, anstatt die IO durchzuführen. Die optimale Puffergröße hängt also von der Firmware und dem Treiber ab. Unter Windows sind gute Werte ein Vielfaches von 32 KB für Festplatten-IO. Die Windows-Dateipufferung, die Speicherzuordnung und all diese Dinge verursachen zusätzlichen Aufwand. Dies ist nur dann sinnvoll, wenn mehrere Lesevorgänge (oder beides) für dieselben Daten im Direktzugriff durchgeführt werden. Wenn Sie also eine große Datei ein einziges Mal sequentiell lesen, möchten Sie nicht, dass das Betriebssystem irgendetwas puffert oder Memcpy's durchführt. Bei der Verwendung von C# gibt es auch Strafen für den Aufruf in das Betriebssystem aufgrund von Marshaling, so dass der Interop-Code möglicherweise Bit der Optimierung benötigen, es sei denn, Sie C++/CLI verwenden.

Manche Leute bevorzugen es, Probleme mit Hardware zu lösen, aber wenn man mehr Zeit als Geld hat, ist es in manchen Szenarien möglich, Dinge so zu optimieren, dass sie auf einem einzigen Computer auf Verbraucherniveau 100-1000 Mal besser funktionieren als auf 1000 Computern in Unternehmenspreisen. Der Grund dafür ist, dass, wenn die Verarbeitung auch latenzempfindlich ist, die Verwendung von mehr als zwei Kernen wahrscheinlich eine zusätzliche Latenz bedeutet. Aus diesem Grund können Treiber Gigabyte/s erreichen, während Unternehmenssoftware am Ende bei Megabyte/s stecken bleibt, wenn alles fertig ist. Was auch immer die Unternehmenssoftware an Berichten, Geschäftslogik und dergleichen leistet, kann wahrscheinlich auch mit Gigabytes/s auf einer Consumer-CPU mit zwei Kernen erledigt werden, wenn sie so geschrieben ist, als hätte man in den 80er Jahren ein Spiel geschrieben. Das berühmteste Beispiel, von dem ich gehört habe, dass die gesamte Geschäftslogik auf diese Weise entwickelt wurde, ist die Devisenbörse LMAX, die einen Teil ihres Ringpuffer-basierten Codes veröffentlicht hat, der angeblich von Netzwerkkartentreibern inspiriert wurde.

Vergessen Sie die ganze Theorie, wenn Sie mit < 1 GB/s zufrieden sind, ist ein möglicher Ausgangspunkt unter Windows der readfile-Quellcode von winimage, es sei denn, Sie wollen sich mit sdk/Treiberbeispielen beschäftigen. Möglicherweise sind einige Quellcodekorrekturen erforderlich, um die Leistung bei SSD-Geschwindigkeiten korrekt zu berechnen. Experimentieren Sie auch mit Puffergrößen. Die Schalter /h multi-threaded und /o overlapped (completion port) IO mit optimaler Puffergröße (probieren Sie 32, 64, 128 KB usw.) ohne Windows-Dateipufferung ergeben meiner Erfahrung nach die beste Leistung beim Lesen von SSD (kalte Daten) bei gleichzeitiger Verarbeitung (verwenden Sie /a für Adler-Verarbeitung, da es sonst zu CPU-gebunden ist).

1voto

Maciek Punkte 18485

Ich scheine mich an ein Projekt zu erinnern, in dem wir große Dateien lasen. Unsere Implementierung verwendete Multithreading - im Grunde starteten n * worker_threads an inkrementellen Offsets der Datei (0, chunk_size, 2xchunk_size, 3x chunk_size ... n-1x chunk_size) und lasen kleinere Informationsbrocken. Ich kann mich nicht mehr genau an unsere Überlegungen dazu erinnern, da jemand anderes das Ganze entworfen hat - die Worker waren nicht das Einzige, aber so haben wir es ungefähr gemacht.

Ich hoffe, es hilft

1voto

Darknight Punkte 2430

Wenn Sie ein Netzwerk von Computern haben, müssen Sie die 10G-Datei auf so viele Client-PCs wie möglich kopieren und jeden Client-PC dazu bringen, einen Offset der Datei zu lesen. Als zusätzlichen Bonus sollte JEDER PC neben dem verteilten Lesen auch Multi-Threading implementieren.

1voto

brian d foy Punkte 124323

Ein Kollege von mir hat seine FIX-Lektüre durch die Umstellung auf 64-Bit-Linux beschleunigt. Wenn es sich lohnt, sollten Sie ein wenig Geld in die Hand nehmen, um eine bessere Hardware zu bekommen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X