Heim > Artikel > Web-Frontend > Ein vorläufiges Verständnis der asynchronen E/A in Nodejs
Dieser Artikel vermittelt Ihnen ein vorläufiges Verständnis der asynchronen E/A in Nodejs. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.
Der Begriff „asynchron“ wurde tatsächlich vor Node geboren. In den meisten höheren Programmiersprachen ist Asynchronität jedoch selten. Unter vielen Hochsprachen oder Betriebsplattformen ist Node der erste, der Asynchronität als Hauptprogrammiermethode und Designkonzept verwendet. [Verwandte Empfehlung: „nodejs Tutorial“]
Asynchrone E/A, ereignisgesteuert und Single-Threaded bilden die Basis von Node, und die ereignisgesteuerten und asynchronen E/A-Designkonzepte von Nginx und Node sind relativ ähnlich . Nginx ist in reinem C geschrieben, bietet eine hervorragende Leistung und verfügt über die leistungsstarke Fähigkeit, Verbindungen für Clients zu verwalten, ist jedoch immer noch durch verschiedene Synchronisierungsprogrammiersprachen eingeschränkt. Aber Node ist vielseitig einsetzbar. Er kann als Server verwendet werden, um eine große Anzahl gleichzeitiger Anforderungen von Clients zu verarbeiten, und er kann auch als Client verwendet werden, um gleichzeitige Anforderungen an verschiedene Anwendungen im Netzwerk zu stellen.
Benutzererfahrung
In ähnlicher Weise kann das Front-End die Blockierung der Benutzeroberfläche durch asynchronen Betrieb beseitigen, aber die Geschwindigkeit, mit der das Front-End Ressourcen erhält, hängt auch von der Reaktionsgeschwindigkeit des Back-Ends ab. Wenn eine Ressource aus der Rückgabe von Daten von zwei verschiedenen Standorten stammt, verbraucht die erste Ressource M Millisekunden und die zweite Ressource N Millisekunden. Wenn die Synchronisierungsmethode verwendet wird, beträgt die zum Abrufen der beiden Ressourcen benötigte Zeit M+N Millisekunden. Bei der asynchronen Methode blockiert der Erwerb der ersten Ressource nicht den Erwerb der zweiten Ressource und die verbrauchte Zeit beträgt max(M,N).
Wenn die Website oder Anwendung weiter wächst, steigen die Werte von M und N linear an, und dann ist die asynchrone Leistung besser als die synchrone.
RessourcenzuweisungNode verwendet einen einzelnen Thread, um Multi-Thread-Deadlock, Zustandssynchronisierung und andere Probleme zu vermeiden. Er verwendet asynchrone E/A, um zu verhindern, dass ein einzelner Thread blockiert, und nutzt die CPU besser aus.
Asynchrone E/A-ImplementierungAsynchrone E/A und nicht blockierende E/A
Ein Merkmal des Blockierens von E/A besteht darin, dass der Aufruf nach dem Aufruf warten muss, bis alle Vorgänge auf Systemkernelebene abgeschlossen sind, bevor der Aufruf beendet wird. Das Blockieren von E/A führt dazu, dass die CPU auf E/A wartet, wodurch Wartezeit verschwendet wird und die Verarbeitungsleistung der CPU nicht vollständig genutzt werden kann.
Um die Leistung zu verbessern, bietet der Kernel nicht blockierende E/A. Der Unterschied zwischen nicht blockierender E/A und blockierender E/A besteht darin, dass nach der Rückkehr der nicht blockierenden E/A die CPU-Zeitscheibe für die Verarbeitung anderer Dinge verwendet werden kann Die Leistungsverbesserung ist offensichtlich, aber aufgrund des Abschlusses ist die E/A nicht abgeschlossen und es werden nicht die von der Geschäftsschicht erwarteten Daten sofort zurückgegeben, sondern nur der aktuelle Aufrufstatus.
Um vollständige Daten zu erhalten, muss die Anwendung den E/A-Vorgang wiederholt aufrufen, um den Abschluss zu bestätigen. Diese Technik des wiederholten Aufrufs, um festzustellen, ob ein Vorgang abgeschlossen ist, wird „Polling“ genannt.
Zu den vorhandenen Polling-Technologien gehören hauptsächlich Read, Select, Poll, Epoll und Kqueue. Hier werde ich nur über das Umfrageprinzip von Epoll sprechen.
epoll ist der effizienteste E/A-Ereignisbenachrichtigungsmechanismus unter Linux. Wenn bei der Abfrage kein E/A-Ereignis erkannt wird, wird es in den Ruhezustand versetzt, bis ein Ereignis eintritt, um es aufzuwecken. Es verwendet tatsächlich Ereignisbenachrichtigungs- und Ausführungsrückrufmethoden, anstatt Abfragen zu durchlaufen, sodass keine CPU verschwendet wird und die Ausführungseffizienz höher ist.
Die Polling-Technologie erfüllt den Bedarf an nicht blockierenden E/A, um sicherzustellen, dass vollständige Daten abgerufen werden. Für das Programm handelt es sich jedoch immer noch um eine Art Synchronisierung, da die Anwendung weiterhin auf die E/A warten muss komplett zurückzugeben, was noch viel Wartezeit kostet. Während des Wartens wird die CPU entweder zum Durchlaufen von Dateideskriptoren verwendet oder sie schläft, während sie darauf wartet, dass Zeit eintrifft.
Vervollständigt die Datenerfassung, indem einige Threads blockierende E/A oder nicht blockierende E/A plus Abfragetechnologie ausführen, sodass ein Thread die Berechnungsverarbeitung durchführen und die erhaltenen Daten über Threads kommunizieren kann by I/O wird übertragen, was die Implementierung asynchroner I/O erleichtert (obwohl dies simuliert wird)
Aber zunächst nutzte Node libeio und libev, um den I/O-Teil unter der *nix-Plattform zu implementieren und so asynchrone I/O zu erreichen. O. In Node v0.9.3 ist ein Thread-Pool implementiert, um asynchrone E/A abzuschließen.
Das IOCP unter Windows bietet bis zu einem gewissen Grad die asynchrone E/A von Li Xiang: Aufrufen asynchroner Methoden, Warten auf Benachrichtigung nach Abschluss der E/A und Ausführen von Rückrufen. Benutzer müssen keine Abfragen in Betracht ziehen. Seine Interna basieren jedoch immer noch auf dem Thread-Pool-Prinzip. Der Unterschied besteht darin, dass diese Thread-Pools vom Systemkernel verwaltet werden.
Aufgrund des Unterschieds zwischen der Windows-Plattform und der *nix-Plattform stellt Node libuv als abstrakte Kapselungsschicht bereit, sodass alle Plattformkompatibilitätsbeurteilungen von dieser Schicht vervollständigt werden und sichergestellt wird, dass der Knoten der oberen Schicht und der benutzerdefinierte Thread der unteren Schicht vorhanden sind pool und IOCP Die Zeichen sind unabhängig.
Wir erwähnen oft, dass Node Single-Threaded ist, was bedeutet, dass JavaScript in einem einzelnen Thread ausgeführt wird. In Node gibt es unabhängig davon, ob es sich um eine *nix- oder eine Windows-Plattform handelt, einen Thread-Pool, der E/A-Aufgaben intern erledigt.
vervollständigt die gesamte asynchrone E/A-Verbindung mit Ereignisschleifen, Beobachtern, Anforderungsobjekten usw.
Die Ereignisschleife ist Nodes eigenes Ausführungsmodell, wodurch Rückruffunktionen sehr verbreitet sind.
Wenn der Prozess startet, erstellt Node eine Schleife ähnlich while(true). Jedes Mal, wenn der Schleifenkörper ausgeführt wird, nennen wir ihn Tick. Der Prozess jedes Ticks besteht darin, zu prüfen, ob ein zu verarbeitendes Ereignis vorhanden ist, und wenn ja, das Ereignis und die zugehörige Rückruffunktion abzurufen. Wenn zugehörige Rückruffunktionen vorhanden sind, führen Sie diese aus. Geben Sie dann die nächste Schleife ein und verlassen Sie den Prozess, wenn keine weiteren Ereignisse zu verarbeiten sind.
In jeder Ereignisschleife gibt es einen oder mehrere Beobachter. Der Prozess zur Bestimmung, ob Ereignisse verarbeitet werden müssen, besteht darin, diese Beobachter zu fragen, ob Ereignisse verarbeitet werden müssen.
In Node stammen Ereignisse hauptsächlich aus Netzwerkanforderungen, Datei-E/A usw. Zu den Beobachtern, die diesen Zeiten entsprechen, gehören Datei-E/A-Beobachter, Netzwerk-E/A-Beobachter usw. Beobachter kategorisierten Ereignisse.
Die Ereignisschleife ist ein typisches Producer/Consumer-Modell. Asynchrone E/A, Netzwerkanforderungen usw. sind die Erzeuger von Ereignissen und stellen dem Knoten ständig verschiedene Arten von Ereignissen zur Verfügung. Diese Ereignisse werden an die entsprechenden Beobachter übermittelt, und die Ereignisschleife übernimmt die Ereignisse von den Beobachtern und verarbeitet sie.
Für asynchrone E/A-Aufrufe des Knotens wird die Rückruffunktion nicht vom Entwickler aufgerufen. Im Übergangsprozess von der Initiierung eines Aufrufs durch JavaScript bis zum Abschluss einer E/A-Operation durch den Kernel gibt es ein Produkt namens Anforderungsobjekt
Die fs.open()-Methode wird unten als kleines Beispiel verwendet.
fs.open = function(path,flags,mode,callback){ //... binding.open(pathModule._makeLong(path), stringToFlags(flags), mode, callback); }
fs.open() wird verwendet, um eine Datei basierend auf dem angegebenen Pfad und den angegebenen Parametern zu öffnen, um einen Dateideskriptor zu erhalten. Dies ist die vorläufige Operation für alle nachfolgenden E/A-Vorgänge. Der Code auf JavaScript-Ebene führt Vorgänge auf niedrigerer Ebene aus, indem er das C++-Kernmodul aufruft.
JavaScript ruft das Kernmodul von Node auf, und das integrierte Modul führt Systemaufrufe über libuv durch. Hier ist die klassische Aufrufmethode in Node. Hier dient libuv als Kapselungsschicht und verfügt über zwei Plattformimplementierungen, die im Wesentlichen die Methode uv_fs_open() aufruft. Während des Aufrufvorgangs von uv_fs_open() werden die von der JavaScript-Ebene und der aktuellen Methode übergebenen Parameter in ein Anforderungsobjekt gekapselt und die Rückruffunktion wird auf die Eigenschaften dieses Objekts festgelegt. Nachdem das Objekt gepackt wurde, wird es in den Thread-Pool verschoben, um auf die Ausführung zu warten.
An diesem Punkt kehrt der JavaScript-Aufruf sofort zurück und die erste Phase des von der JavaScript-Ebene initiierten asynchronen Aufrufs endet. JavaScript-Threads können weiterhin nachfolgende Vorgänge für die aktuelle Aufgabe ausführen.
Das Anforderungsobjekt ist ein wichtiges Zwischenprodukt im asynchronen E/A-Prozess. Alle Zustände werden in diesem Objekt gespeichert, einschließlich des Sendens an den Thread-Pool, um auf die Ausführung und Rückrufverarbeitung zu warten, nachdem der E/A-Vorgang abgeschlossen ist.
Das Zusammenstellen des Anforderungsobjekts und das Senden an den E/A-Thread-Pool zur Ausführung ist nur der erste Teil des Abschlusses einer E/A, und die Rückrufbenachrichtigung ist der zweite Teil.
Nachdem die E/A-Operation im Thread-Pool aufgerufen wurde, wird das erhaltene Ergebnis im Attribut req->result gespeichert und anschließend wird PostQueueCompletionStatus() aufgerufen, um IOCP darüber zu informieren, dass die aktuelle Objektoperation abgeschlossen wurde.
Zu diesem Zeitpunkt ist der gesamte asynchrone E/A-Prozess vollständig abgeschlossen.
Die Ereignisschleife, der Beobachter, das Anforderungsobjekt und der E/A-Thread-Pool bilden zusammen die Grundelemente des asynchronen E/A-Modells des Knotens.
Nachdem wir es geklärt haben, können wir mehrere Schlüsselwörter für asynchrone E/A extrahieren: Einzelthread, Ereignisschleife, Beobachter und E/A-Thread-Pool. Ein einzelner Thread und ein Thread-Pool scheinen ein gewisses Paradoxon zu sein. Da JavaScript Single-Threaded ist, ist es leicht zu verstehen, dass es die Vorteile von Multi-Core-CPUs nicht voll ausnutzen kann. Tatsächlich ist Node selbst in Node, abgesehen davon, dass JavaScript Single-Threaded ist, tatsächlich Multi-Threaded, aber der E/A-Thread verbraucht weniger CPU. Abgesehen davon, dass Benutzercode nicht parallel ausgeführt werden kann, können alle E/A (Festplatten-E/A, Netzwerk-E/A usw.) parallel ausgeführt werden.
Weitere Kenntnisse zum Thema Programmierung finden Sie unter: Programmiervideos! !
Das obige ist der detaillierte Inhalt vonEin vorläufiges Verständnis der asynchronen E/A in Nodejs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!