Warum ist Node.js Single-Threaded? [geschlossen]


255

In PHP- (oder Java / ASP.NET / Ruby-) Webservern wird jede Clientanforderung in einem neuen Thread instanziiert. Aber in Node.js laufen alle Clients auf demselben Thread (sie können sogar dieselben Variablen gemeinsam nutzen!). Ich verstehe, dass E / A-Operationen ereignisbasiert sind, sodass sie die Haupt-Thread-Schleife nicht blockieren.

Was ich nicht verstehe ist, WARUM der Autor von Node es als Single-Thread ausgewählt hat? Das macht es schwierig. Zum Beispiel kann ich keine CPU-intensive Funktion ausführen, da sie den Hauptthread blockiert (und neue Clientanforderungen blockiert werden), sodass ich einen Prozess erzeugen muss (was bedeutet, dass ich eine separate JavaScript-Datei erstellen und einen anderen Knotenprozess ausführen muss es). In PHP-CPU blockieren intensive Aufgaben jedoch keine anderen Clients, da sich, wie bereits erwähnt, jeder Client in einem anderen Thread befindet. Was sind die Vorteile gegenüber Multithread-Webservern?

Hinweis: Ich habe Clustering verwendet, um dies zu umgehen, aber es ist nicht schön.


12
Ich habe mir kürzlich ein gutes Video (29 Minuten) angesehen, in dem einige der Theorien hinter Node erklärt wurden. Ich denke sogar, dass der Typ über CPU-intensive Aufgaben spricht und kurz, wie man damit umgeht: youtube.com/watch?v=L0pjVcIsU6A
whirlwin

24
Sie wissen das vielleicht, aber um klar zu sein, Node.js ist kein Single-Threaded. Ihr JavaScript-Code wird mit einem Thread ausgeführt, aber E / A-Vorgänge und andere Dinge, die Plugins ausführen können, werden aus einem Thread-Pool ausgeführt. Node.js bietet Ihnen viele Vorteile von Multithreading, ohne sich mit Multithread-Code befassen zu müssen. Außerdem haben die Mitwirkenden von Node.j nicht die Single-Threaded-Natur von JavaScript ausgewählt, sondern die Autoren von JavaScript. Ich kann mir keine Möglichkeit vorstellen, wie JS in einem Multithread-Kontext arbeiten könnte, aber selbst wenn dies der Fall wäre, ist V8 nicht so geschrieben, wie es Node.js als JavaScript-Engine verwendet.
Brad

5
PHP ist mehr Single-Threaded als JavaScript. Sie denken wahrscheinlich an Servermodule wie FastCGI oder mod_php. Sie vergleichen Node.js also tatsächlich mit Apache, Nginx oder IIS - nicht mit PHP, Java oder Ruby.
Álvaro González

34
Der Knoten ist nicht Single-Threaded. Es ist ein weit verbreitetes Missverständnis. Selbst einfach node -e 'setTimeout(()=>{},1000);' & ps -T h $! | wc -l; kill $!zeigt fünf Threads auf meinem System an. Die Hauptereignisschleife ist Single-Threaded (es wäre nicht sehr sinnvoll, wenn dies nicht der Fall wäre), aber Node ist stark Multithread-fähig und Sie können Multithread-Single-Prozess-Anwendungen schreiben, wenn Sie möchten. Ich würde gerne eine umfassende Antwort darüber schreiben, aber einige Leute haben beschlossen, Ihre Frage zu schließen, damit ich nicht kann. Ich stimme dafür, es wieder zu öffnen. Wenn es mehr Stimmen bekommt und wieder geöffnet wird, dann erwähne mich bitte im Kommentar.
rsp

2
@rsp danke für deinen Kommentar, aber ich meinte im Haupt-Thread nicht i / o verwandt. Wenn Sie eine CPU-bezogene Funktion ausführen, z. B. eine große for-Schleife, die etwas bewirkt, beendet der Server die Verarbeitung von Verbindungen. Das heißt, der Server ist zu diesem Zeitpunkt unbrauchbar. Wir verwenden also Hacks wie Cluster, um etwas so Einfaches zu tun, anstatt wie bei den meisten Servern jede Verbindung von Natur aus zu fädeln. jxcore.com hat versucht, dies zu beheben, aber dann werden spezielle / modifizierte Knoten-Plugins verwendet, was es für mich im Wesentlichen unbrauchbar macht.
Foreyez

Antworten:


292

Node.js wurde explizit als Experiment in der asynchronen Verarbeitung erstellt. Die Theorie war, dass die asynchrone Verarbeitung auf einem einzelnen Thread unter typischen Weblasten mehr Leistung und Skalierbarkeit bieten kann als die typische threadbasierte Implementierung.

Und weisst du was? Meiner Meinung nach hat sich diese Theorie bestätigt. Eine node.js-App, die keine CPU-intensiven Aufgaben ausführt, kann Tausende von Verbindungen gleichzeitig ausführen als Apache, IIS oder andere threadbasierte Server.

Die asynchrone Natur mit einem Thread macht die Dinge kompliziert. Aber denkst du ehrlich, es ist komplizierter als das Einfädeln? Eine Rennbedingung kann Ihren gesamten Monat ruinieren! Oder leeren Sie Ihren Thread-Pool aufgrund einer Einstellung irgendwo und beobachten Sie, wie sich Ihre Antwortzeit auf ein Crawlen verlangsamt! Ganz zu schweigen von Deadlocks, Prioritätsinversionen und all den anderen Drehungen, die mit Multithreading einhergehen.

Am Ende denke ich nicht, dass es allgemein besser oder schlechter ist; es ist anders und manchmal ist es besser und manchmal nicht. Verwenden Sie das richtige Werkzeug für den Job.


26
Aber Webserver erledigen normalerweise VIEL CPU-intensive Dinge, die nicht NUR zum Abrufen von Datenbanken erforderlich sind. Wir müssen verarbeiten, was wir abrufen, und die meiste Zeit viel Geschäftslogik ausführen, bevor wir es dem Kunden zur Verfügung stellen.
Foreyez

22
Also nur Arbeiter spawnen, na ja! Das ist der ganze Deal mit Node.js. Schweres Material kann in einem anderen Prozess ausgeführt werden, und Sie verarbeiten es, was zu einem leichten Rückruf führt.
MaiaVictor

7
Das Problem dabei ist, dass pro Worker ein Prozess auf Betriebssystemebene ausgeführt wird. Sie werden sehen, dass sie den Befehl "ps" verwenden. Das bedeutet also möglicherweise, dass Tausende von Prozessen gleichzeitig auf der Maschine ausgeführt werden - das ist verrückt!
Foreyez

9
@foreyez, Sie benötigen keinen Prozess pro Benutzer. Sie haben die Wahl, wie Sie die Last aufteilen möchten. Außerdem macht nicht jeder eine Menge CPU-intensives Zeug. Node ist ein Werkzeug für einen Job ... vielleicht nicht Ihr Job, aber viele Arten von Jobs.
Brad

15
Eigentlich möchte ich, dass @foreyez diese Aussage bestätigt, dass "Webserver normalerweise VIEL (sic) von CPU-intensivem Material sind". Nach meiner Erfahrung tun sie das nicht. Oder vielleicht unterscheidet sich meine Definition von "CPU-intensiv" von seiner. Das Konvertieren von Produktdaten in eine Benutzeroberfläche ist weder CPU-intensiv noch berechnet es Aufträge oder ähnliches. Der größte Teil des Webs ist ziemlich transaktional. CPU-intensives Zeug ist das Konvertieren von Videos, das Konvertieren von Bildformaten usw. Ein Großteil davon ist auf Datei-E / A zurückzuführen, die der Knoten eigentlich ziemlich gut macht. Und erleichtert das Auslagern in einen anderen Prozess, der der Konvertierung gewidmet ist.
Paul

62

Das Problem mit dem Modell "Ein Thread pro Anforderung" für einen Server besteht darin, dass sie im Vergleich zum Thread-Modell für Ereignisschleifen für mehrere Szenarien nicht gut skaliert werden können.

In E / A-intensiven Szenarien warten die Anforderungen in der Regel die meiste Zeit auf den Abschluss der E / A. Während dieser Zeit werden im Modell "Ein Thread pro Anforderung" die mit dem Thread verknüpften Ressourcen (z. B. Speicher) nicht verwendet, und der Speicher ist der begrenzende Faktor. Im Ereignisschleifenmodell wählt der Schleifenthread das nächste zu behandelnde Ereignis (E / A beendet) aus. Der Thread ist also immer beschäftigt (wenn Sie ihn natürlich richtig programmieren).

Das Ereignisschleifenmodell, da alle neuen Dinge glänzend erscheinen und die Lösung für alle Probleme, aber welches Modell verwendet werden soll, hängt von dem Szenario ab, das Sie angehen müssen. Wenn Sie ein intensives E / A-Szenario haben (wie ein Proxy), gilt das Ereignisbasismodell, während ein CPU-intensives Szenario mit einer geringen Anzahl gleichzeitiger Prozesse am besten mit dem Thread-basierten Modell funktioniert.

In der realen Welt werden die meisten Szenarien etwas in der Mitte liegen. Sie müssen das tatsächliche Bedürfnis nach Skalierbarkeit mit der Komplexität der Entwicklung in Einklang bringen, um die richtige Architektur zu finden (z. B. ein Ereignisbasis-Frontend, das für die CPU-intensiven Aufgaben an das Backend delegiert. Das Frontend benötigt nur wenig Ressourcen, die auf die Aufgabe warten Ergebnis.) Wie bei jedem verteilten System sind einige Anstrengungen erforderlich, damit es funktioniert.

Wenn Sie nach der Silberkugel suchen, die ohne Anstrengung zu jedem Szenario passt, haben Sie eine Kugel im Fuß.


8
Node.js ist aufgrund der fehlenden Unterstützung für Multithreading in Version 8 auf die Nur-Ereignis-Verarbeitung beschränkt. Nun, in der Javascript-Sprache selbst fehlen die erforderlichen Funktionen, sodass jede Implementierung schwierig wird. Das ist meiner Meinung nach der Hauptschuldige von Node.js. In anderen Sprachen können Sie auswählen, was Sie möchten. Oder eine Mischung aus beiden Modellen wie Java NIO.
FrameGrace

2
@Kazaag, Moderne Web - Server tun ein Threadpool halten. Sie erzeugen nicht nur dumm einen neuen Thread pro Seitenladevorgang. Das sind die älteren Webserver.
Pacerier

1
@Pacerier Ich habe nie gesagt, dass ein neuer Thread erzeugt wird, aber jeder Thread wird einer Anforderung zugewiesen, bis die Anforderung abgeschlossen ist.
Kazaag

2
@Kazaag Es ist definitiv keine allgemeine Regel, dass "jeder Thread einer Anfrage zugeordnet ist, bis die Anfrage abgeschlossen ist". Das heißt, in .Net (einschließlich der Verarbeitung von HTTP-Anforderungen) kann und sollte eine asynchrone (aufgabenbasierte) Programmierung verwendet werden. Dadurch werden Threads freigegeben, während auf den Abschluss von E / A- und anderen asynchronen Vorgängen gewartet wird. Dies gilt auch für die Programmierung auf hoher Ebene, dh für MVC / API-Controller. In der Praxis können also 20 HTTP-Anforderungen ausstehen, aber nur ein aktiver Thread.
user3285954

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.