2012-04-09 10 views
6

Ich habe ein Programm, das viele Daten generiert und es in eine Warteschlange zum Schreiben stellt, aber das Problem ist, dass es Daten schneller generiert, als ich gerade schreibe (wodurch es zu maximalem Speicher kommt und zu verlangsamen beginnt). Reihenfolge spielt keine Rolle, da ich die Datei später analysieren möchte.Was ist der schnellste Weg, um eine große Menge an Daten aus dem Speicher in eine Datei zu schreiben?

Ich sah mich ein bisschen um und fand ein paar Fragen, die mir halfen meinen aktuellen Prozess zu entwerfen (aber ich finde es immer noch langsam). Hier ist mein Code so weit:

//...background multi-threaded process keeps building the queue.. 
FileWriter writer = new FileWriter("foo.txt",true); 
     BufferedWriter bufferWritter = new BufferedWriter(writer); 
     while(!queue_of_stuff_to_write.isEmpty()) { 
      String data = solutions.poll().data; 
      bufferWritter.newLine(); 
      bufferWritter.write(data); 
     } 
     bufferWritter.close(); 

ich Programmierung ziemlich neu bin, damit ich vielleicht diese falsche Beurteilung (vielleicht ein Hardware-Problem, wie ich bin mit EC2), aber ist es eine sehr schnell die Warteschlange Ergebnisse Dump in eine Datei oder wenn mein Ansatz in Ordnung ist, kann ich es irgendwie verbessern? Da die Reihenfolge keine Rolle spielt, ist es sinnvoller, in mehrere Dateien auf mehreren Laufwerken zu schreiben? Will Threading es schneller machen? Usw. Ich bin mir nicht genau sicher, ob die beste Herangehensweise und irgendwelche Vorschläge großartig wären. Mein Ziel ist es, die Ergebnisse der Warteschlange zu speichern (sorry keine Ausgabe an/dev/null :-) und Speicherverbrauch für meine App so niedrig wie möglich halten (Ich bin nicht 100% sicher, aber die Warteschlange füllt 15gig, also ich gehe davon aus, dass es eine 15gig + Datei sein wird).

Fastest way to write huge data in text file Java (realisierte soll ich gepuffert Writer) Concurrent file write in Java on Windows (mich sehen, dass vielleicht Multi-Threading schreibt war keine gute Idee)

+0

Ich verstehe CPU-Geschwindigkeit> Festplatte Geschwindigkeit, so Schreiben wird wahrscheinlich immer zu Verarbeitung verlieren, ich versuche nur herauszufinden, wie man hd Geschwindigkeit hilft, ein wenig näher an die Handhabung. –

+0

Viel hängt davon ab, was Ihr Flaschenhals ist. Ich vermute, wenn Sie die Bandbreite Ihrer Disk-IO (die Ihre Frage zu sein scheint) ausschöpfen können Sie auch Ihr Konto (in Bezug auf die Kosten) Max. Ich stimme zu multi-threading der Schreibvorgang wird nicht viel helfen. –

+0

Eine grobe Berechnung ist, dass 15 GB jedes Mal $ 4 kostet. –

Antwort

2

Mit Blick auf diesen Code, eine Sache, die in den Sinn kommt, ist die Zeichencodierung. Sie schreiben Strings, aber letztendlich sind es Bytes, die zu den Streams gehen. Ein Writer-Zeichen-zu-Byte-Kodierung unter der Haube, und es macht es in demselben Thread, der das Schreiben behandelt. Das kann bedeuten, dass Zeit für die Codierung aufgewendet wird, die Schreibvorgänge verzögert, was die Geschwindigkeit verringern könnte, mit der Daten geschrieben werden.

Eine einfache Änderung einer Warteschlange von byte[] anstelle von String, tun die Codierung in den Fäden zu verwenden, wäre, die auf die Warteschlange drücken, und haben den IO-Code verwenden, um eine BufferedOutputStream anstatt eine BufferedWriter.

Dies kann auch Speicherverbrauch reduzieren, wenn der codierte Text im Durchschnitt weniger als zwei Bytes pro Zeichen belegt. Für lateinischen Text und UTF-8-Codierung ist dies normalerweise der Fall.

Allerdings vermute ich, dass es wahrscheinlich ist, dass Sie einfach Daten schneller generieren, als Ihr IO-Subsystem damit umgehen kann.Sie müssen Ihr IO-Subsystem schneller machen - entweder indem Sie ein schnelleres verwenden (wenn Sie auf EC2 sind, vielleicht eine schnellere Instanz mieten oder in ein anderes Backend schreiben - SQS vs EBS vs lokale Festplatte, etc) oder durch Gruppierung mehrere IO Subsysteme irgendwie parallel zusammen.

0

Ich denke, so lange wie Sie Ihre Daten aus Berechnungen produzieren und zu tun Wenn Sie Ihre Daten nicht aus einer anderen Datenquelle laden, ist das Schreiben immer langsamer als das Generieren Ihrer Daten.

Sie können versuchen, Ihre Daten in mehreren Dateien (nicht in der gleichen Datei -> aufgrund von Synchronisationsproblemen) in mehreren Threads schreiben (aber ich denke, das wird Ihr Problem nicht beheben).

Ist es möglich, dass Sie auf den schreibenden Teil Ihrer Anwendung warten, um den Vorgang zu beenden und Ihre Berechnungen fortzusetzen?

Ein anderer Ansatz ist: Leeren Sie Ihre Warteschlange? Reduziert solutions.poll() Ihre Lösungswarteschlange?

0

Schreiben in andere Dateien mit mehreren Threads ist eine gute Idee. Außerdem sollten Sie die BufferedWriters-Puffergröße festlegen, die Sie über den Konstruktor ausführen können. Versuchen Sie, mit einem 10 Mb Puffer zu initialisieren, und sehen Sie, ob das hilft

+0

Ist es? Das Schreiben von zwei Dateien parallel zu derselben mechanischen Festplatte dauert viel länger als das Schreiben der ersten und dann der anderen. –

1

Ja, das Schreiben mehrerer Dateien auf mehrere Laufwerke sollte helfen, und wenn nichts anderes gleichzeitig auf diese Laufwerke geschrieben wird, sollte die Leistung linear mit der Anzahl der Laufwerke skaliert werden, bis E/A nicht mehr der Flaschenhals ist. Sie können auch ein paar andere Optimierungen ausprobieren, um die Leistung noch zu steigern.

Wenn Sie große Dateien generieren und die Festplatte einfach nicht mithalten kann, können Sie mit GZIPOutputStream die Ausgabe verkleinern - was wiederum die Anzahl der Festplatten-I/O reduziert. Für nicht zufälligen Text können Sie normalerweise eine Komprimierungsrate von mindestens 2x-10x erwarten.

//...background multi-threaded process keeps building the queue.. 
    OutputStream out = new FileOutputStream("foo.txt",true); 
    OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(out)); 
    BufferedWriter bufferWriter = new BufferedWriter(writer); 
    while(!queue_of_stuff_to_write.isEmpty()) { 
     String data = solutions.poll().data; 
     bufferWriter.newLine(); 
     bufferWriter.write(data); 
    } 
    bufferWriter.close(); 

Wenn Sie regelmäßig sind ausgibt (das heißt, sich wiederholende) Daten, möchten Sie vielleicht auch zu einem anderen Ausgabeformat Wechsel zu berücksichtigen - beispielsweise eine binäre Codierung der Daten. Abhängig von der Struktur Ihrer Daten ist es möglicherweise effizienter, sie in einer Datenbank zu speichern. Wenn Sie XML ausgeben und wirklich an XML festhalten möchten, sollten Sie in ein Binary XML Format wie EXI oder Fast InfoSet schauen.

Verwandte Themen