2009-08-28 3 views
11

Wir müssen lesen und verschiedene Arten von Nachrichten/run Statistiken auf einer 10 GB-Textdatei, beispiels einem FIX Motor log zu zählen. Wir verwenden Linux, 32-Bit, 4 CPUs, Intel, in Perl codieren aber die Sprache spielt keine Rolle. Ich habe einige interessante Tipps in Tim Brays WideFinder project gefunden. Wir haben jedoch herausgefunden, dass die Verwendung der Speicherzuordnung von Natur aus durch die 32-Bit-Architektur begrenzt ist.Was ist der schnellste Weg, 10-GB-Dateien von der Festplatte zu lesen?

Wir haben versucht, mehrere Prozesse, die schneller zu arbeiten scheint, wenn wir die Datei parallel verarbeiten mit 4 Prozesse auf 4 CPUs. Hinzufügen von Multi-Threading verlangsamt es, vielleicht wegen der Kosten der Kontextwechsel. Wir haben versucht, die Größe des Thread-Pool zu ändern, aber das ist immer noch langsamer als einfache Multi-Prozess-Version. Der Speicherzuordnungsteil ist nicht sehr stabil, manchmal dauert es 80 Sekunden und manchmal 7 Sekunden auf einer 2 GB Datei, vielleicht von Seitenfehlern oder etwas in Bezug auf virtuellen Speicherverbrauch. Wie auch immer, kann Mmap über 4 GB auf einer 32-Bit-Architektur nicht maßstäblich.

Wir haben versucht, Perl IPC::Mmap und Sys::Mmap. Sieht in Map-Reduce als gut, aber das Problem ist wirklich I/O gebunden, die Verarbeitung selbst ausreichend schnell ist.

Also haben wir beschlossen, das grundlegende I/O durch Abstimmen Puffergröße, um zu versuchen zu optimieren, Typ usw.

Kann jemand, der von einem bestehenden Projekt bewusst ist, wo dieses Problem effizient in jeder Sprache/Plattform gelöst wurde Zeigen Sie auf einen nützlichen Link oder schlagen Sie eine Richtung vor?

+2

Was ist die rohe Leistung auf einer einzigen CPU für 2G? Sie müssen wahrscheinlich feststellen, ob die E/A das Problem oder die CPU-Berechnungen ist. – Cervo

+2

Wenn Sie wirklich an die Festplatte (IO) gebunden sind, sollten Sie wahrscheinlich schnellere Festplatten, mehr Festplatten (in RAID0, RAID5, RAID10 usw.) oder eine 64-Bit-Maschine mit genügend Speicher zum Speichern der Datei kaufen eine RAM-Disk. Jeder vernünftige einzelne Datenträger sollte in der Lage sein, 50 MB/s zu ziehen; mehrere schnelle Festplatten sollten in der Lage sein, Sie auf mindestens 300 MB/s zu schieben. – derobert

+1

Ich würde empfehlen, nicht Sys :: Mmap, sondern File-Map (aus Gründen, die in der Dokumentation des letzteren angegeben sind) zu verwenden. In jedem Fall möchten Sie wahrscheinlich nicht IPC :: Mmap verwenden. –

Antwort

9

Die meiste Zeit werden Sie E/A-gebunden nicht CPU-gebunden sein, also lesen Sie einfach diese Datei über normale Perl I/O und verarbeiten Sie sie in einem Thread. Wenn Sie nicht beweisen, dass Sie mehr I/O als Ihre Single-CPU-Arbeit tun können, verschwenden Sie Ihre Zeit mit nichts mehr. Wie auch immer, du solltest fragen: Warum in aller Welt ist das in einer riesigen Datei? Warum auf der Erde teilen sie es nicht in einer vernünftigen Weise, wenn sie es erzeugen? Es wäre mehr Arbeit wert. Dann können Sie es in separate I/O-Kanäle legen und mehr CPUs verwenden (wenn Sie keine Art von RAID 0 oder NAS oder ... verwenden).

Messen, nicht davon ausgehen. Vergessen Sie nicht, die Caches vor jedem Test zu leeren. Denken Sie daran, dass serialisierte I/O eine Größenordnung schneller als zufällig ist.

0

Ich erinnere mich an ein Projekt, in dem wir große Dateien lasen. Unsere Implementierung verwendete Multithreading - im Grunde begannen n * worker_threads die Offsets der Datei zu inkrementieren (0, chunk_size, 2xchunk_size, 3x chunk_size ... n-1x) chunk_size) und liest kleinere Informationen. Ich kann mich nicht genau an unsere Argumentation erinnern, da jemand anderes das Ganze gemacht hat - die Arbeiter waren nicht das Einzige, aber so haben wir es gemacht.

Hoffe, es

Sie hilft
2

Haben Sie daran gedacht, die Datei von Streaming und alle interessante Ergebnisse zu einer sekundären Datei Ausfiltern? (Wiederholen Sie dies, bis Sie eine verwaltbare Datei haben).

3

Vielleicht haben Sie bereits in diesem Forum Thread gelesen, aber wenn nicht:

http://www.perlmonks.org/?node_id=512221

Es Perl beschreibt die Verwendung es zu tun line-by-line, und die Benutzer scheinen zu denken, Perl durchaus in der Lage ist davon.

Oh, ist es möglich, die Datei von einer RAID-Array zu verarbeiten? Wenn Sie mehrere gespiegelte Platten haben, kann die Lesegeschwindigkeit verbessert werden. Der Wettbewerb um Festplattenressourcen kann dazu führen, dass Ihr Multiple-Threads-Versuch nicht funktioniert.

Viel Glück.

3

Ich wünschte, ich wüsste mehr über den Inhalt Ihrer Datei, aber nicht zu wissen, dass es Text ist, das klingt wie eine ausgezeichnete MapReduce Art von Problem.

PS, das schnellste Lesen einer Datei ist ein linearer Lesevorgang. cat file > /dev/null sollte die Geschwindigkeit sein, mit der die Datei gelesen werden kann.

+3

In der Tat; Mein Kollege, der an einem ähnlichen Problem arbeitete, benutzte das Timing von cat, um andere Probleme in der Lesegeschwindigkeit von Dateien aufzuspüren. NFS war eine schreckliche Zeit. :( –

1

Grundsätzlich müssen Sie "Divide and Conquer", wenn Sie ein Netzwerk von Computern haben, dann kopieren Sie die 10G-Datei auf so viele Client-PCs wie möglich, jeden Client-PC einen Offset der Datei zu lesen. Als zusätzlichen Bonus erhalten Sie JEDEN PC, um Multi-Threading zusätzlich zum verteilten Lesen zu implementieren.

+3

"das Problem ist wirklich IO gebunden" <--- viel Glück beim Kopieren der Datei auf eine Maschine schneller als die Festplatten können es lesen. – derobert

1

Die Datei einmal analysieren und Zeile für Zeile lesen. Legen Sie die Ergebnisse in eine Tabelle in einer anständigen Datenbank. Führen Sie so viele Abfragen aus, wie Sie möchten. Füttere das Biest regelmäßig mit neuen eingehenden Daten.

Erkennen Sie, dass das Manipulieren einer 10-GB-Datei, das Übertragen über das (selbst wenn lokale) Netzwerk, das Erforschen komplizierter Lösungen usw. Zeit brauchen.

+2

Feed-Datenbank und Ausführen von Abfragen kann Magnitude mehr Zeit als alle Verarbeitung in Perl. Es ist aus meiner Erfahrung, dass Sie sogar Massenlast und MySQL verwenden, was einer der schnellsten Ansätze ist, was Sie verwenden können.) –

+1

Sobald Sie die Daten in einer * anständigen * Datenbank haben, können Sie mit geringen zusätzlichen Kosten so viele Abfragen ausführen, wie Sie möchten (auch diejenigen, von denen Sie nicht wussten, dass Sie sie ausführen wollten). –

1

Ich habe einen Kollegen, der seine FIX-Lesung beschleunigt hat, indem er zu 64-Bit-Linux ging. Wenn es etwas wert ist, lassen Sie ein wenig Geld fallen, um etwas schickere Hardware zu bekommen.

4

Dies hängt davon ab, welche Art von Vorverarbeitung Sie und wann durchführen können. Auf einigen der Systeme, die wir haben, gzip wir solche großen Textdateien und reduzieren sie auf 1/5 bis 1/7 ihrer ursprünglichen Größe. Ein Teil von dem, was das ermöglicht, ist, dass wir diese Dateien erst Stunden nach ihrer Erstellung verarbeiten müssen, und zum Zeitpunkt der Erstellung haben wir keine andere Last auf den Maschinen.

Verarbeitung ist mehr oder weniger in der Art von zcat thesfiles | getan ourprocessing. (Nun, es ist über Unix-Sockets getan, obwohl mit einem benutzerdefinierten zcat). Es handelt CPU-Zeit für Festplatten-E/A-Zeit, und für unser System, das gut wert war. Es gibt natürlich viele Variablen, die dies zu einem sehr schlechten Design für ein bestimmtes System machen können.

1

hmmm, aber was ist falsch mit dem Befehl read() in C? Normalerweise hat ein 2GB Limit, , also rufen Sie es einfach 5 Mal hintereinander auf. Das sollte ziemlich schnell sein.

1

Wenn Sie I/O-gebunden sind und Ihre Datei auf einer einzelnen Festplatte gespeichert ist, gibt es nicht viel zu tun. Ein geradliniger linearer Scan mit nur einem Thread über die gesamte Datei hinweg ist der schnellste Weg, um die Daten von der Festplatte zu entfernen. Die Verwendung großer Puffergrößen könnte ein wenig helfen.

Wenn Sie den Schreiber der Datei davon überzeugen können, ihn auf mehrere Festplatten/Maschinen zu übertragen, könnten Sie über Multithreading nachdenken (ein Thread pro Lesekopf, wobei jeder Thread die Daten von einem einzelnen Streifen liest).

0

Es ist nicht in dem Problem angegeben, dass Reihenfolge wirklich zählt oder nicht.Also, teilen Sie die Datei in gleiche Teile sagen je 1GB, und da Sie mehrere CPUs verwenden, dann werden mehrere Threads kein Problem sein, so lesen Sie jede Datei mit separaten Thread, und verwenden RAM der Kapazität> 10 GB, dann alle Ihre Inhalte würde im RAM von mehreren Threads gelesen werden.

1

Da Sie die Plattform und die Sprache keine Rolle spielt ...

Wenn Sie eine stabile Leistung, die so schnell wie das Quellmedium ermöglicht, den einzigen Weg, ich weiß, dass dies auf getan werden kann, Windows besteht aus überlappenden, nicht OS-gepufferten, aufeinander ausgerichteten sequentiellen Lesevorgängen. Sie können wahrscheinlich einige GB/s mit zwei oder drei Puffern erreichen, darüber hinaus benötigen Sie irgendwann einen Ringpuffer (ein Writer, 1+ Leser), um ein Kopieren zu vermeiden. Die genaue Implementierung hängt von den Treibern/APIs ab. Wenn auf dem Thread (sowohl im Kernel als auch im Usermode) ein Speicherkopiervorgang stattfindet, der sich mit dem E/A-Vorgang befasst, wird offensichtlich der größere Puffer kopiert, je mehr Zeit dafür verschwendet wird, anstatt den E/A auszuführen. Die optimale Puffergröße hängt also von der Firmware und dem Treiber ab. Unter Windows sind die zu testenden Werte ein Vielfaches von 32 KB für Disk IO. Die Windows-Dateipufferung, die Speicherzuordnung und all diese Dinge bringen zusätzlichen Aufwand. Nur gut, wenn beide (oder beide) Mehrfachlesevorgänge derselben Daten in wahlfreier Zugriffsart ausgeführt werden. Wenn Sie also eine große Datei sequenziell einmal lesen möchten, möchten Sie nicht, dass das Betriebssystem etwas puffert oder irgendwelche Mempys ausführt. Wenn Sie C# verwenden, gibt es auch Strafen für das Aufrufen des Betriebssystems aufgrund von Marshalling. Daher muss der Interop-Code möglicherweise optimiert werden, es sei denn, Sie verwenden C++/CLI.

Manche Leute ziehen es vor, Hardware bei Problemen zu werfen, aber wenn Sie mehr Zeit als Geld haben, ist es in manchen Szenarien möglich, die Dinge auf einem einzigen Consumer-Level-Computer 100-1000x besser zu machen als 1000er-Computer. Der Grund dafür ist, dass, wenn die Verarbeitung auch latenzempfindlich ist, wahrscheinlich mehr Latenz hinzugefügt wird, wenn zwei Kerne verwendet werden. Das ist der Grund, warum Treiber Gigabytes/s pushen können, während Enterprise-Software bis zum Ende der Zeit bei Megabytes/s stecken bleibt. Was auch immer Berichterstattung, Geschäftslogik und so die Unternehmenssoftware tun, kann wahrscheinlich auch bei Gigabyte/s auf zwei Kernverbraucher-CPUs erfolgen, wenn man so schreibt, als wäre man in den 80ern schon einmal ein Spiel geschrieben. Das berühmteste Beispiel, von dem ich gehört habe, dass es sich auf diese Weise seiner gesamten Geschäftslogik annäherte, ist der LMAX-Forex-Austausch, der einige seiner Ringpuffer-basierten Codes veröffentlichte, die angeblich von Netzwerkkartentreibern inspiriert wurden.

Vergessen Sie die ganze Theorie, wenn Sie mit < 1 GB/s zufrieden sind, einen möglichen Ausgangspunkt auf Windows habe ich auf readfile Quelle von winimage, wenn Sie in SDK/Treiber Proben graben wollen. Es kann einige Quellcode-Fixes benötigen, um die Perf-Funktion bei SSD-Geschwindigkeiten korrekt zu berechnen. Experimentieren Sie auch mit Puffergrößen. Die Switches/h Multithread und/o überlappt (Completion Port) IO mit optimaler Puffergröße (versuchen 32,64,128 KB usw.) ohne Windows-Dateipufferung meiner Erfahrung nach beste Leistung beim Lesen von SSD (kalte Daten) gleichzeitig Verarbeitung (verwenden Sie die/a für Adler-Verarbeitung, da sie sonst zu CPU-gebunden ist).