2010-11-01 12 views
14

Ich frage mich, ob es eine Möglichkeit gibt, Unix-Textdateien schneller miteinander zu verketten als cat läuft?Was ist der schnellste Weg, mehrere Dateien zu catchen?

Hier ist das Problem, mit dem ich konfrontiert bin. Ich bin String Verarbeitung einer Textdatei ~ 100G in Größe. Ich versuche, die Laufzeit zu verbessern, indem ich die Datei in mehrere hundert kleinere Dateien zerlege und parallel verarbeite. Am Ende ziehe ich die resultierenden Dateien wieder zusammen. Die Lese-/Schreibzeit der Datei selbst nimmt Stunden in Anspruch. Ich mag einen Weg finden, den folgenden Bereiche zu verbessern:

cat file1 file2 file3 ... fileN >> newBigFile 
  1. Dies erfordert die doppelten Festplattenspeicher als file1 ... fileN nimmt 100G und dann newBigFile nimmt eine anderen 100Gb und dann file1. .. fileN bekommt

  2. Die Daten sind bereits in file1 entfernt ... fileN lesen die cat >> erleidet und tun und Zeit schreiben, wenn alles, was ich wirklich für die wieder erscheinen als 1 Datei ...

    zu Hunderte von Dateien benötigen, ist
+0

Es klingt wie Sie etwas mit ein bisschen mehr Muskeln als ein Unix-Shell werden sollte. –

+0

Ich habe keine Ahnung, wovon ich spreche, aber ist es möglich, die Datei zu manipulieren oder so etwas? Was ich tun musste, war nicht, Daten zu duplizieren, sondern mehrere Dateien zusammen wieder in 1 zu zeichnen? – Wing

Antwort

4

Schnell, aber nicht frei Lösung? Holen Sie sich ein SSD-Laufwerk oder Flash-PCIe-basierten Speicher. Wenn dies regelmäßig durchgeführt werden muss, ist eine Erhöhung der Festplatten-E/A-Geschwindigkeit die kostengünstigste und schnellste Beschleunigung, die Sie erzielen können.

+0

Danke, aber leider kann ich nicht die Datei-Server und Geräte ... – Wing

+2

Natürlich kann Ihr Umstand dies der Gesellschaft ändern, sofern dies nur, wenn es als Ergänzung zu einem vorhandenen Server Plattenspeicher (statt Ersatz) zu Management vorgestellt, es kann in Betracht gezogen werden. Wenn Sie eine SSD haben, die nur für diese Aufgabe verwendet wird, und es spart täglich 2 Stunden Bearbeitungszeit, ich denke, dass sie von den Kosteneinsparungen überzeugt sein würden. –

4

Vielleicht dd wäre schneller, weil Sie Zeug zwischen Katze und der Schale nicht übergeben müssten. Etwas wie:

mv file1 newBigFile 
dd if=file2 of=newBigFile seek=$(stat -c %s newBigFile) 
+1

ich denke definitiv, dass dd, kombiniert mit dem Löschen der Dateien, wie Sie sie kopieren, wie Robie Basak vorgeschlagen, wird für die am meisten rekombinierende Lösung, kurz vor der Implementierung eines benutzerdefinierten cp/unlink Befehl mit mmap. Ich bin überzeugt, dass nichts effizienter wäre, als die Spaltung vollständig zu eliminieren. – frankc

1

alles, was ich wirklich brauchen, ist für die Hunderte von Dateien als 1 Datei wieder zu erscheinen ...

Der Grund ist es nicht sinnvoll ist, nur Dateien verbinden auf diese Weise in einem Dateisystem Ebene, da Textdateien normalerweise einen Plattenblock nicht genau füllen, so dass die Daten in nachfolgenden Dateien nach oben verschoben werden müssten, um die Lücken zu füllen, was zu einer Reihe von Lese-/Schreibvorgängen auf jeden Fall führt.

4

Ist es möglich, dass Sie die Datei nicht teilen? Verarbeiten Sie die Datei stattdessen in Blöcken, indem Sie den Dateizeiger in jedem Ihrer parallelen Worker festlegen. Wenn die Datei zeilenorientiert verarbeitet werden muss, ist das schwieriger, aber dennoch machbar. Jeder Worker muss verstehen, dass er, anstatt mit dem Offset zu beginnen, den Sie ihm geben, zuerst Byte für Byte bis zum nächsten Zeilenumbruch +1 suchen muss. Jeder Worker muss außerdem verstehen, dass er die festgelegte Anzahl von Bytes nicht verarbeitet, sondern die erste neue Zeile nach der festgelegten Anzahl von Bytes verarbeiten muss, die er verarbeiten soll.

Die tatsächliche Zuweisung und Einstellung des Dateizeigers ist ziemlich einfach. Wenn es n Worker gibt, verarbeitet jeder n/Dateigröße Bytes und der Dateizeiger beginnt mit der Worker-Nummer * n/file_size.

Gibt es einen Grund, dass diese Art von Plan nicht ausreicht?

+0

Anstatt die Worker zu modifizieren, könnte die Shell den Arbeitern eine 'stdin' liefern, die bereits das Segment ist, an dem sie arbeiten soll, zum Beispiel mit' sed', um einen Linienbereich auszuwählen.Wenn die Ausgabe koordiniert werden soll, könnte GNU Parallel dabei helfen. –

+0

Die ganze Sache ist in Perl gemacht, wo das ursprüngliche Skript versucht, String-Manipulationen durch die ganze 100G-Datei seriell durchzuführen. Im Moment habe ich es die Datei aufteilen und die Stücke über fork() verarbeiten, aber jetzt die Lese-/Schreibzeit ist Engpässen der Laufzeit. Ich muss den ersten Split nicht machen, wie du gesagt hast, aber ich muss immer noch die verarbeiteten Chunks schreiben und sie dann wieder in 1 Datei zusammenfügen, richtig? – Wing

+0

Wenn ich die Datei nicht aufspalte und jeder untergeordnete Prozess die ursprüngliche 100G-Datei liest, die an verschiedenen Zeilen arbeitet, bekomme ich einen Engpass von 200 Prozessen, die versuchen, dieselbe Datei zu lesen? – Wing

6

Wenn Dateien wieder zusammen verketten, können Sie die kleinen Dateien löschen, da sie angehängt bekommen:

for file in file1 file2 file3 ... fileN; do 
    cat "$file" >> bigFile && rm "$file" 
done 

Dies würde vermeiden doppelt so viel Speicherplatz benötigen.

Es gibt keine andere Art und Weise von Zauberhand-Dateien auf magische Weise verketten machen. Die Dateisystem-API hat einfach keine Funktion, die das tut.

6

Wenn Sie keinen Direktzugriff in die letzte große Datei benötigen (das heißt, können Sie es nur einmal von Anfang lesen bis zum Ende), können Sie Ihre Hunderte von Zwischendateien erscheinen als machen. Wo man normalerweise

$ consume big-file.txt 

tun würde

$ consume <(cat file1 file2 ... fileN) 

stattdessen tun Dies verwendet Unix process substitution, manchmal auch als "anonyme Named Pipes."

Sie können auch in der Lage sein, Zeit und Raum zu sparen, indem Sie Ihre Eingabe Aufspalten und die Verarbeitung zur gleichen Zeit zu tun; GNU Parallel hat eine --pipe switch, die genau dies tun wird. Es kann die Ausgaben auch wieder in eine große Datei zusammenfügen, möglicherweise mit weniger Speicherplatz, da es nur Anzahl der Kerne Stücke auf der Festplatte auf einmal zu halten braucht. Wenn Sie buchstäblich Hunderte von Prozessen gleichzeitig ausführen, wird Parallel Ihre Effizienz erheblich verbessern, indem Sie die Parallelität Ihrer Maschine optimieren können. Ich empfehle es sehr.

+0

Ich habe es nicht getestet dies, aber es klingt wie der nützlichste Vorschlag – Michael

+0

Prozesssubstitution sieht fantastisch aus, weil es Dinge nicht auf die Festplatte legt. Sie können also "consume <(cmd1 file1) <(cmd2 file2) <(cmd3 file3)" verwenden. Hier entspricht es jedoch dem traditionelleren "cat file1 file2 ... | consume". – dfrankow

1

Es gibt so etwas wie zu viel Gleichzeitigkeit.

Eine bessere Möglichkeit, dies zu tun, wäre, Lesezugriffe in die Datei über die gewünschten Bereiche zu verwenden und sie niemals tatsächlich aufzuteilen und nur die Anzahl der Dateien als Anzahl der physischen CPU/Kerne in der Maschine zu verarbeiten. Das ist, es sei denn, dass die Festplatte mit IOPS auch überschwemmt, dann sollten Sie zurückschneiden, bis die Festplatte nicht der Engpass ist.

Was Sie tun, ist Tonnen IOPS zu erzeugen, und es gibt keinen Weg, um die Physik von ihm.

2

Ich glaube, dies ist der schnellste Weg, um Katze alle enthaltenen Dateien im selben Ordner:

$ ls [path to folder] | while read p; do cat $p; done 
+0

Schön =) Das hat peachy funktioniert. brauchte ein Echo; vor dem getan. – Kieveli

Verwandte Themen