Wie ich es verstehe, ist eine der Konsequenzen des Easted IO-Modells von Node die Unfähigkeit, einen Node-Prozess, der (zum Beispiel) Daten über einen TCP-Socket empfängt, zu blockieren, sobald Sie Ihr empfangendes Event angeschlossen haben Handler (oder sonst begonnen, auf Daten zu hören).
Wenn der Empfänger die eingehenden Daten nicht schnell genug verarbeiten kann, kann "unbegrenzte Parallelität" resultieren, wobei der Knoten unter der Haube weiterhin Daten aus dem Socket so schnell wie möglich liest und neue Datenereignisse für das Ereignis plant Schleife statt Block auf dem Socket, bis der Prozess schließlich aus dem Speicher ausgeführt wird und stirbt.
Der Empfänger kann dem Knoten nicht mitteilen, dass er sein Lesen verlangsamen soll. Dies würde sonst dazu führen, dass TCPs eingebaute Flusskontrollmechanismen eingreifen und dem Sender anzeigen, dass er langsamer werden muss.
Erstens, ist das, was ich bis jetzt beschrieben habe, genau? Gibt es etwas, das ich vermisst habe, das es Knoten ermöglicht, diese Situation zu vermeiden?
Eine der vielbeworbenen Funktionen von Node Streams ist die automatische Handhabung von Gegendruck.
AFAIK, der einzige Weg, wie ein schreibbarer Stream (eines TCP-Sockets) erkennen kann, ob er verlangsamen muss oder nicht, ist socket.bufferSize
(zeigt an, wie viele Daten in den Socket geschrieben, aber noch nicht gesendet wurden). Da der Knoten am empfangenden Ende immer so schnell wie möglich liest, kann dies nur eine langsame Netzwerkverbindung zwischen Sender und Empfänger anzeigen, und NICHT, ob der Empfänger nicht mithalten kann.
Zweitens kann der automatische Gegendruck von Node Streams irgendwie in dieser Situation funktionieren, um mit einem Empfänger fertig zu werden, der nicht mithalten kann?
Es scheint auch, dass dieses Problem Browser betrifft, die Daten über Websockets empfangen, aus dem ähnlichen Grund, dass die websockets-API keinen Mechanismus bereitstellt, um dem Browser mitzuteilen, sein Lesen aus dem Socket zu verlangsamen.
Ist die einzige Lösung für dieses Problem für Node (und Browser, die websockets verwenden), einen manuellen Ablaufsteuerungsmechanismus auf Anwendungsebene zu implementieren, um den sendenden Prozess explizit zu verlangsamen?
Um Ihre erste Frage zu beantworten, glaube ich, dass Ihr Verständnis nicht stimmt - zumindest nicht, wenn Daten zwischen Streams gepumpt werden. Wenn Sie die Dokumentation für die Funktion pipe () lesen, werden Sie feststellen, dass dies ausdrücklich angegeben ist verwaltet den Datenfluss automatisch, so dass das Ziel nicht von einem schnell lesbaren Datenstrom überlastet wird.
Die zugrunde liegende Implementierung von pipe () kümmert sich um das gesamte schwere Heben für Sie. Der Eingabestream (ein lesbarer -Stream) gibt weiterhin Daten Ereignisse bis zum Ausgabestream (ein Stream Beschreibbar ) ) ist voll. Abgesehen davon, wenn ich mich richtig erinnere, wird der Stream false zurückgeben, wenn Sie versuchen, Daten zu schreiben, die derzeit nicht verarbeitet werden können. An dieser Stelle wird die Pipe pause () den Stream "Lesbar" anzeigen, der verhindert, dass weitere Datenereignisse ausgegeben werden. Daher wird die Ereignisschleife Ihren Speicher nicht füllen und erschöpfen, noch wird sie Ereignisse ausgeben, die einfach verloren sind. Stattdessen bleibt das Lesbare so lange pausiert, bis der Writable-Stream ein Ablauf -Ereignis auslöst. An diesem Punkt wird die Pipe resume () den lesbaren Stream aufnehmen.
Die geheime Soße pumpt einen Strom in einen anderen, der automatisch den Gegendruck für Sie regelt. Dies beantwortet hoffentlich Ihre zweite Frage, nämlich dass der Node dies durch einfaches Pipettieren von Streams automatisch bewältigen kann und tut.
Und schließlich gibt es wirklich keine Notwendigkeit, dies manuell zu implementieren (es sei denn, Sie schreiben einen neuen Stream von Grund auf), da es bereits für Sie bereitgestellt wird. :)
Die Handhabung all dieser Dinge ist nicht einfach, wie im Node-Blog-Beitrag, der die streams2 API ankündigte, zugelassen wurde im Knoten. Es ist eine großartige Ressource und bietet sicherlich viel mehr Informationen als ich hier könnte. Ein kleiner Fehler, der nicht ganz offensichtlich ist, dass Sie aber wissen sollten, aus der Dokumentation hier und aus Gründen der Rückwärtskompatibilität:
Wenn Sie einen Datenereignis-Listener anhängen, wird der Stream in den fließenden Modus versetzt und die Daten werden an Ihren Handler übergeben, sobald dieser verfügbar ist.
Seien Sie sich also bewusst, dass das Anfügen des Datenereignis-Listeners bei dem Versuch, etwas im Stream zu beobachten, den Stream grundlegend auf die alte Art und Weise ändert, Dinge zu tun. Frag mich wie ich weiß .
Tags und Links node.js stream backpressure