Verwendung des Drain-Ereignisses von stream.Writable in Node.js

8

In Node.js verwende ich die Methode fs.createWriteStream , um Daten an eine lokale Datei anzufügen. In der Node-Dokumentation erwähnen sie das drain -Ereignis bei Verwendung von fs.createWriteStream , aber ich verstehe es nicht.

%Vor%

Wie kann ich im obigen Code das Drain-Ereignis verwenden? Wird das Ereignis unten ordnungsgemäß verwendet?

%Vor%     
sachin 21.09.2013, 12:17
quelle

2 Antworten

15

Das Ereignis drain wird verwendet, wenn der interne Puffer eines schreibbaren Streams geleert wurde.

Dies kann nur passieren, wenn die Größe des internen Puffers einmal die highWaterMark -Eigenschaft überschritten hat. Dies sind die maximalen Datenbytes, die im internen Puffer eines schreibbaren Streams gespeichert werden können, bis das Lesen aus der Datenquelle beendet wird.

Die Ursache für so etwas kann auf Setups zurückzuführen sein, bei denen eine Datenquelle schneller aus einem Stream gelesen wird als auf eine andere Ressource geschrieben werden kann. Nimm zum Beispiel zwei Streams:

%Vor%

Stellen Sie sich nun vor, dass die Datei read auf einer SSD liegt und mit 500MB / s lesen kann und write auf einer Festplatte ist, die nur in 150MB/s schreiben kann. Der Schreibstrom kann nicht mithalten und beginnt, Daten im internen Puffer zu speichern. Sobald der Puffer das highWaterMark erreicht hat, was standardmäßig 16 KB ist, werden die Schreibvorgänge false zurückgeben, und der Strom wird intern einen Abfluss in die Warteschlange stellen. Sobald die Länge des internen Puffers 0 ist, wird das Ereignis drain ausgelöst.

So funktioniert ein Abfluss:

%Vor%

Und das sind die Voraussetzungen für einen Abfluss, der Teil der Funktion writeOrBuffer ist:

%Vor%

Um zu sehen, wie das drain -Ereignis verwendet wird, nehmen Sie das Beispiel aus der Node.js-Dokumentation.

%Vor%

Das Ziel der Funktion besteht darin, 1.000.000 Mal in einen beschreibbaren Stream zu schreiben. Was passiert, ist eine Variable ok wird auf true gesetzt, und eine Schleife wird nur ausgeführt, wenn ok wahr ist. Für jede Schleifeniteration wird der Wert von ok auf den Wert von stream.write() gesetzt, der den Wert false zurückgibt, wenn ein drain erforderlich ist. Wenn ok falsch wird, wartet der Ereignishandler für drain und setzt den Schreibvorgang fort.

In Bezug auf Ihren Code müssen Sie das drain -Ereignis nicht verwenden, da Sie nur einmal direkt nach dem Öffnen Ihres Streams schreiben. Da Sie noch nichts in den Stream geschrieben haben, ist der interne Puffer leer, und Sie müssten mindestens 16 KB in Blöcken schreiben, damit das Ereignis drain ausgelöst wird. Das drain -Ereignis dient zum Schreiben vieler Male mit mehr Daten als die highWaterMark -Einstellung Ihres schreibbaren Streams.

    
hexacyanide 21.09.2013 14:35
quelle
4

Stellen Sie sich vor, Sie verbinden zwei Streams mit sehr unterschiedlichen Bandbreiten, zum Beispiel das Hochladen einer lokalen Datei auf einen langsamen Server. Der (schnelle) Dateistrom sendet Daten schneller als der (langsame) Socket-Stream ihn verbrauchen kann.

In dieser Situation speichert node.js die Daten im Speicher, bis der langsame Stream die Möglichkeit hat, sie zu verarbeiten. Dies kann problematisch werden, wenn die Datei sehr groß ist.

Um dies zu vermeiden, gibt Stream.write false zurück, wenn der zugrunde liegende Systempuffer voll ist. Wenn Sie mit dem Schreiben aufhören, gibt der Stream später ein drain -Ereignis aus, um anzuzeigen, dass der Systempuffer geleert hat und es angemessen ist, erneut zu schreiben.

Sie können pause/resume den lesbaren Stream verwenden und die Bandbreite des lesbaren Streams steuern.

Besser: Sie können readable.pipe(writable) verwenden, was das für Sie tut.

BEARBEITEN : Es gibt einen Fehler in Ihrem Code: unabhängig davon, was write zurückgibt, wurden Ihre Daten geschrieben. Sie müssen es nicht erneut versuchen. In Ihrem Fall schreiben Sie data zweimal.

So etwas würde funktionieren:

%Vor%     
Laurent Perrin 21.09.2013 12:47
quelle

Tags und Links