Ich weiß, dass node.js ein single-threaded, asynchroner, nicht blockierender E / A ist. Ich habe viel darüber gelesen. Zum Beispiel verwendet PHP einen Thread pro Anfrage, aber Knoten verwendet nur einen Thread für alle, so.
Angenommen, es gibt drei Anfragen a, b, c, die gleichzeitig auf dem Server node.js ankommen. Drei dieser Anforderungen erfordern eine große Blockierungsoperation, z. B. möchten alle die gleiche große Datei lesen.
Wie werden dann die Anfragen in die Warteschlange gestellt, in welcher Reihenfolge wird die Blockierung durchgeführt und in welchen Sequenzen werden die Antworten versendet? Natürlich mit wievielen Threads?
Bitte sagen Sie mir die Sequenzen von Anfrage zu Antwort für drei Anfragen.
Im Folgenden finden Sie eine Beschreibung einer Abfolge von Ereignissen für Ihre drei Anforderungen:
Obwohl also nur eine Anfrage gleichzeitig ausgeführt wird, können mehrere Anfragen gleichzeitig "in Bearbeitung" oder "im Flug" sein. Dies wird manchmal als kooperatives Multitasking bezeichnet, anstelle von "präemptivem" Multitasking mit mehreren nativen Threads, bei denen das System jederzeit zwischen Threads wechseln kann. Ein bestimmter Javascript-Thread wird ausgeführt, bis er zum System und dann zurückkehrt und nur dann kann ein anderes Stück Javascript gestartet werden. Da ein Teil von Javascript nicht blockierende asynchrone Operationen auslösen kann, kann der JavaScript-Thread zum System zurückkehren (wodurch andere Teile von Javascript aktiviert werden), während asynchrone Operationen noch ausstehen. Wenn diese Vorgänge abgeschlossen sind, werden sie ein Ereignis in die Ereigniswarteschlange stellen und wenn anderes Javascript ausgeführt wird und dieses Ereignis an den Anfang der Warteschlange gelangt, wird es ausgeführt.
Single-Threaded
Der entscheidende Punkt hier ist, dass ein bestimmter Javascript-Thread ausgeführt wird, bis er zum System zurückkehrt. Wenn während der Ausführung einige asynchrone Vorgänge (z. B. Datei-I / O oder Netzwerk) gestartet werden, wird nach Abschluss dieser Ereignisse ein Ereignis in die Ereigniswarteschlange eingefügt, und wenn die JS-Engine fertig ist, werden zuvor alle Ereignisse ausgeführt Dieses Ereignis wird bearbeitet und ein Callback wird aufgerufen und der Callback wird ausgeführt.
Diese single-threaded-Eigenschaft vereinfacht die Behandlung von Parallelität im Vergleich zu einem Multi-Threaded-Modell erheblich. In einer Multithread-Umgebung, in der jede einzelne Anfrage ihren eigenen Thread startet, sind JEDE Daten, die geteilt werden sollen, selbst eine einfache Variable, einer Race Condition ausgesetzt und müssen mit einem Mutex geschützt werden, bevor jemand sie lesen kann.
In Javascript, da keine gleichzeitige Ausführung mehrerer Anfragen erfolgt, wird kein Mutex für den einfachen Zugriff auf gemeinsam genutzte Variablen benötigt. An dem Punkt, an dem Javascript eine Variable liest, wird per Definition kein anderes Javascript in diesem Moment ausgeführt (single threaded).
Knoten.js verwendet Threads
Eine technische Besonderheit ist, dass nur die Ausführung Ihres Javascript single threaded ist. Die Interna von node.js verwenden für einige Dinge selbst Threads. Zum Beispiel verwendet asynchrone Datei-E / A tatsächlich native Threads. Netzwerk-E / A verwendet keine Threads (es verwendet native ereignisgesteuerte Netzwerke).
Aber diese Verwendung von Threads in den Interna von node.js hat keinen direkten Einfluss auf die Ausführung von Javascript. Es gibt immer nur einen einzigen Thread von Javascript, der gleichzeitig ausgeführt wird.
Rassenbedingungen
Es kann immer noch Race-Bedingungen für den Zustand geben, der gerade geändert wird, wenn eine asynchrone Operation gestartet wird. Dies ist jedoch viel seltener als in einer Umgebung mit mehreren Threads und viel einfacher zu identifizieren und zu schützen diese Fälle. Als ein Beispiel für eine Race Condition, die existieren kann, habe ich einen einfachen Server, der Messwerte von mehreren Temperatursonden alle 10 Sekunden mit einem Intervall-Timer misst. Er sammelt die Daten von all diesen Temperaturmessungen und schreibt diese Daten jede Stunde auf die Festplatte. Es verwendet asynchrone E / A, um die Daten auf die Festplatte zu schreiben. Da jedoch verschiedene asynchrone Datei-E / A-Vorgänge zum Schreiben der Daten auf die Festplatte verwendet werden, ist es möglich, dass der Intervallzeitgeber zwischen einigen dieser asynchronen Datei-E / A-Vorgänge ausgelöst wird, die die Daten verursachen, auf denen sich der Server befindet die Mitte des Schreibens auf die Festplatte geändert werden. Dies ist schlecht und kann dazu führen, dass inkonsistente Daten geschrieben werden. In einer einfachen Welt könnte dies vermieden werden, indem eine Kopie aller Daten erstellt wird, bevor sie mit dem Schreiben auf die Festplatte beginnt. Wenn also eine neue Temperaturmessung erfolgt, während die Daten auf die Festplatte geschrieben werden, ist die Kopie nicht betroffen wird immer noch einen konsistenten Datensatz auf die Festplatte schreiben. Aber im Fall dieses Servers können die Daten groß sein und der Speicher auf dem Server ist klein (es ist ein Raspberry Pi Server), so dass es nicht praktisch ist, eine Kopie aller Daten im Speicher zu erstellen.
Das Problem wird also gelöst, indem ein Flag gesetzt wird, wenn die Daten gerade auf den Datenträger geschrieben werden, und dann das Flag gelöscht wird, wenn die Daten auf den Datenträger geschrieben wurden. Wenn ein Intervallzeitgeber ausgelöst wird, während dieses Flag gesetzt ist, werden die neuen Daten in eine separate Warteschlange gestellt, und die Kerndaten, die gerade auf die Festplatte geschrieben werden, werden NICHT geändert. Wenn die Daten fertig sind, werden sie auf die Platte geschrieben, und sie prüft die Warteschlange und alle Temperaturdaten, die dort gefunden werden, werden dann zu den Temperaturdaten im Speicher hinzugefügt. Die Integrität dessen, was gerade auf die Festplatte geschrieben wird, bleibt erhalten. Mein Server protokolliert jedes Mal ein Ereignis, wenn diese "Wettlaufbedingung" getroffen wird und Daten deswegen in die Warteschlange gestellt werden. Und, siehe da, es passiert hin und wieder und der Code, um die Integrität der Daten zu erhalten, funktioniert.
Tags und Links node.js nonblocking single-threaded