Was wäre besser für gleichzeitige Aufgaben auf node.js? Fasern? Web-Worker? oder Threads?


111

Ich bin vor einiger Zeit über node.js gestolpert und mag es sehr. Aber bald stellte ich fest, dass es an der Fähigkeit mangelte, CPU-intensive Aufgaben auszuführen. Also fing ich an zu googeln und bekam diese Antworten, um das Problem zu lösen: Fasern, Webworker und Threads (Thread-a-Gogo). Welcher zu verwenden ist, ist eine Verwirrung und einer von ihnen muss definitiv verwendet werden - was ist der Zweck eines Servers, der nur gut in E / A ist und sonst nichts? Vorschläge benötigt!

AKTUALISIEREN:

Ich dachte an einen Weg zu spät; Ich brauche nur Vorschläge darüber. Nun, woran ich dachte, war Folgendes: Lassen Sie uns einige Threads haben (mit thread_a_gogo oder vielleicht Webworkern). Wenn wir jetzt mehr davon brauchen, können wir mehr schaffen. Der Erstellungsprozess ist jedoch begrenzt. (nicht vom System impliziert, aber wahrscheinlich wegen Overhead). Wenn wir das Limit überschreiten, können wir einen neuen Knoten teilen und Threads darüber erstellen. Auf diese Weise kann es weitergehen, bis wir eine Grenze erreichen (schließlich haben auch Prozesse einen großen Overhead). Wenn dieses Limit erreicht ist, beginnen wir, Aufgaben in die Warteschlange zu stellen. Immer wenn ein Thread frei wird, wird ihm eine neue Aufgabe zugewiesen. Auf diese Weise kann es reibungslos weitergehen.

Daran habe ich gedacht. Ist diese Idee gut? Ich bin ein bisschen neu in all diesen Prozessen und Threads, also habe ich kein Fachwissen darin. Bitte teilen Sie Ihre Meinungen.

Vielen Dank. :) :)


Bitte beachten Sie: Worker sind eine Browserspezifikation - keine Javascript-Funktion.
FredTheWebGuy

Nun, das sehe ich. Meine Frage betraf node.js - Servercode und nicht clientseitig!
Parth Thakkar

Nur eine Klarstellung - ich sehe, dass die ursprüngliche Frage über Webworker in NodeJs war, was unmöglich ist - NodeJs verwendet "Threads". Es gibt jedoch ein NodeJS-Modul, das die WebWorker-Syntax innerhalb der NodeJs-Laufzeit ermöglicht.
FredTheWebGuy

Antworten:


329

Node hat ein völlig anderes Paradigma und sobald es richtig erfasst ist, ist es einfacher, diese andere Art der Problemlösung zu erkennen. Sie benötigen niemals mehrere Threads in einer Knotenanwendung (1), da Sie auf unterschiedliche Weise dasselbe tun. Sie erstellen mehrere Prozesse. Es unterscheidet sich jedoch erheblich von der Prefork-PMM von Apache Web Server.

Nehmen wir zunächst an, wir haben nur einen CPU-Kern und entwickeln eine Anwendung (auf Node-Art), um einige Arbeiten auszuführen. Unsere Aufgabe ist es, eine große Datei zu verarbeiten, die byteweise über ihren Inhalt läuft. Der beste Weg für unsere Software besteht darin, die Arbeit am Anfang der Datei zu beginnen und sie Byte für Byte bis zum Ende zu verfolgen.

- Hey, Hasan, ich nehme an, du bist entweder ein Neuling oder eine sehr alte Schule aus der Zeit meines Großvaters !!! Warum erstellen Sie nicht einige Threads und machen es viel schneller?

- Oh, wir haben nur einen CPU-Kern.

-- Na und? Erstellen Sie einige Threads Mann, machen Sie es schneller!

- So funktioniert es nicht. Wenn ich Threads erstelle, werde ich es langsamer machen. Weil ich dem System viel Overhead für das Wechseln zwischen Threads hinzufügen werde, um ihnen eine angemessene Zeit zu geben und innerhalb meines Prozesses zu versuchen, zwischen diesen Threads zu kommunizieren. Zusätzlich zu all diesen Fakten muss ich mir auch überlegen, wie ich einen einzelnen Job in mehrere Teile aufteilen kann, die parallel ausgeführt werden können.

- Okay, okay, ich sehe, du bist arm. Verwenden wir meinen Computer, er hat 32 Kerne!

- Wow, du bist großartig, mein lieber Freund, vielen Dank. Ich schätze es!

Dann kehren wir zur Arbeit zurück. Jetzt haben wir dank unseres reichen Freundes 32 CPU-Kerne. Die Regeln, die wir einhalten müssen, haben sich gerade geändert. Jetzt wollen wir all diesen Reichtum nutzen, den wir bekommen.

Um mehrere Kerne zu verwenden, müssen wir einen Weg finden, unsere Arbeit in Teile zu unterteilen, die wir parallel verarbeiten können. Wenn es nicht Node wäre, würden wir dafür Threads verwenden. 32 Threads, einer für jeden CPU-Kern. Da wir jedoch einen Knoten haben, werden wir 32 Knotenprozesse erstellen.

Threads können eine gute Alternative zu Node-Prozessen sein, vielleicht sogar eine bessere. aber nur in einer bestimmten Art von Arbeit, in der die Arbeit bereits definiert ist und wir die vollständige Kontrolle darüber haben, wie wir damit umgehen sollen. Abgesehen davon ist Node's Weg für jede andere Art von Problem, bei dem der Job von außen auf eine Weise kommt, über die wir keine Kontrolle haben und die wir so schnell wie möglich beantworten möchten, unbestreitbar überlegen.

- Hey, Hasan, arbeitest du immer noch mit einem Thread? Was ist los mit dir, Mann? Ich habe dir gerade das zur Verfügung gestellt, was du wolltest. Du hast keine Ausreden mehr. Erstellen Sie Threads und beschleunigen Sie sie.

- Ich habe die Arbeit in Teile geteilt und jeder Prozess wird parallel an einem dieser Teile arbeiten.

- Warum erstellst du keine Threads?

- Entschuldigung, ich denke nicht, dass es brauchbar ist. Sie können Ihren Computer mitnehmen, wenn Sie möchten?

- Nein okay, ich bin cool, ich verstehe nur nicht, warum du keine Threads verwendest?

- Danke für den Computer. :) Ich habe die Arbeit bereits in Teile geteilt und Prozesse erstellt, um diese Teile parallel zu bearbeiten. Alle CPU-Kerne werden voll ausgelastet. Ich könnte dies mit Threads anstelle von Prozessen tun; Aber Node hat diesen Weg und mein Chef Parth Thakkar möchte, dass ich Node benutze.

- Okay, lassen Sie mich wissen, wenn Sie einen anderen Computer benötigen. : p

Wenn ich 33 statt 32 Prozesse erstelle, pausiert der Scheduler des Betriebssystems einen Thread, startet den anderen, pausiert ihn nach einigen Zyklen, startet den anderen erneut ... Dies ist unnötiger Overhead. Ich will es nicht. Auf einem System mit 32 Kernen würde ich nicht einmal genau 32 Prozesse erstellen wollen, 31 können schöner sein . Weil nicht nur meine Anwendung auf diesem System funktioniert. Ein wenig Platz für andere Dinge zu lassen, kann gut sein, besonders wenn wir 32 Zimmer haben.

Ich glaube, wir sind jetzt auf der gleichen Seite, wenn es darum geht, Prozessoren für CPU-intensive Aufgaben voll auszunutzen .

- Hmm, Hasan, es tut mir leid, dass ich dich ein wenig verspottet habe. Ich glaube, ich verstehe dich jetzt besser. Aber es gibt noch etwas, für das ich eine Erklärung brauche: Worum geht es bei der Ausführung von Hunderten von Threads? Ich habe überall gelesen, dass Threads viel schneller zu erstellen und dumm sind als Forking-Prozesse. Sie verzweigen Prozesse anstelle von Threads und denken, dass dies der höchste Wert ist, den Sie mit Node erzielen würden. Ist Node dann nicht für diese Art von Arbeit geeignet?

- Keine Sorge, ich bin auch cool. Jeder sagt diese Dinge, also denke ich, ich bin es gewohnt, sie zu hören.

-- So? Knoten ist nicht gut dafür?

- Node ist dafür perfekt geeignet, obwohl Threads auch gut sein können. Wie für den Aufwand für die Thread- / Prozesserstellung; Bei Dingen, die Sie häufig wiederholen, zählt jede Millisekunde. Ich erstelle jedoch nur 32 Prozesse und es wird eine winzige Zeit dauern. Es wird nur einmal passieren. Es wird keinen Unterschied machen.

- Wann möchte ich dann Tausende von Threads erstellen?

- Sie möchten niemals Tausende von Threads erstellen. Auf einem System, das Arbeiten von außen ausführt, z. B. einem Webserver, der HTTP-Anforderungen verarbeitet. Wenn Sie für jede Anforderung einen Thread verwenden, erstellen Sie viele Threads, viele davon.

- Knoten ist aber anders? Richtig?

-- Ja genau. Hier scheint Node wirklich. Wie ein Thread viel leichter als ein Prozess ist, ist ein Funktionsaufruf viel leichter als ein Thread. Der Knoten ruft Funktionen auf, anstatt Threads zu erstellen. Im Beispiel eines Webservers verursacht jede eingehende Anforderung einen Funktionsaufruf.

-- Hmm, interessant; Sie können jedoch nur eine Funktion gleichzeitig ausführen, wenn Sie nicht mehrere Threads verwenden. Wie kann dies funktionieren, wenn viele Anfragen gleichzeitig auf dem Webserver eingehen?

- Sie haben vollkommen Recht damit, wie Funktionen einzeln ausgeführt werden, niemals zwei parallel. Ich meine, in einem einzelnen Prozess wird jeweils nur ein Codebereich ausgeführt. Der OS Scheduler pausiert diese Funktion nicht und wechselt zu einer anderen, es sei denn, er pausiert den Prozess, um einem anderen Prozess Zeit zu geben, nicht einem anderen Thread in unserem Prozess. (2)

- Wie kann ein Prozess dann zwei Anfragen gleichzeitig bearbeiten?

- Ein Prozess kann Zehntausende von Anforderungen gleichzeitig verarbeiten, solange unser System über genügend Ressourcen (RAM, Netzwerk usw.) verfügt. Wie diese Funktionen ausgeführt werden, ist DER SCHLÜSSELUNTERSCHIED.

- Hmm, sollte ich jetzt aufgeregt sein?

- Vielleicht :) Node führt eine Schleife über eine Warteschlange. In dieser Warteschlange befinden sich unsere Jobs, dh die Anrufe, mit denen wir begonnen haben, eingehende Anforderungen zu verarbeiten. Der wichtigste Punkt hierbei ist die Art und Weise, wie wir unsere Funktionen für die Ausführung entwerfen. Anstatt eine Anfrage zu bearbeiten und den Anrufer warten zu lassen, bis wir den Job beendet haben, beenden wir unsere Funktion schnell, nachdem wir eine akzeptable Menge an Arbeit erledigt haben. Wenn wir an einem Punkt angelangt sind, an dem wir auf eine andere Komponente warten müssen, um etwas zu erledigen, und uns einen Wert zurückgeben müssen, anstatt darauf zu warten, beenden wir einfach unsere Funktion und fügen den Rest der Arbeit der Warteschlange hinzu.

- Es klingt zu komplex?

- Nein, nein, ich könnte komplex klingen. Aber das System selbst ist sehr einfach und macht durchaus Sinn.

Jetzt möchte ich aufhören, den Dialog zwischen diesen beiden Entwicklern zu zitieren, und meine Antwort nach einem letzten kurzen Beispiel für die Funktionsweise dieser Funktionen beenden.

Auf diese Weise machen wir das, was OS Scheduler normalerweise tun würde. Wir unterbrechen unsere Arbeit irgendwann und lassen andere Funktionsaufrufe (wie andere Threads in einer Umgebung mit mehreren Threads) laufen, bis wir wieder an der Reihe sind. Dies ist viel besser, als die Arbeit dem OS Scheduler zu überlassen, der versucht, jedem Thread auf dem System nur Zeit zu geben. Wir wissen, was wir viel besser machen als OS Scheduler, und es wird erwartet, dass wir aufhören, wenn wir aufhören sollten.

Im Folgenden finden Sie ein einfaches Beispiel, in dem wir eine Datei öffnen und lesen, um die Daten zu bearbeiten.

Synchroner Weg:

Open File
Repeat This:    
    Read Some
    Do the work

Asynchroner Weg:

Open File and Do this when it is ready: // Our function returns
    Repeat this:
        Read Some and when it is ready: // Returns again
            Do some work

Wie Sie sehen, fordert unsere Funktion das System auf, eine Datei zu öffnen, und wartet nicht darauf, dass sie geöffnet wird. Es beendet sich selbst, indem es die nächsten Schritte bereitstellt, nachdem die Datei fertig ist. Bei unserer Rückkehr führt Node andere Funktionsaufrufe in der Warteschlange aus. Nachdem alle Funktionen ausgeführt wurden, wechselt die Ereignisschleife zur nächsten Runde ...

Zusammenfassend hat Node ein völlig anderes Paradigma als die Multithread-Entwicklung. das heißt aber nicht, dass es an Dingen mangelt. Bei einem synchronen Job (bei dem wir die Reihenfolge und Art der Verarbeitung festlegen können) funktioniert dies ebenso wie die Multithread-Parallelität. Für einen Job, der wie Anfragen an einen Server von außen kommt, ist er einfach überlegen.


(1) Es sei denn, Sie erstellen Bibliotheken in anderen Sprachen wie C / C ++. In diesem Fall erstellen Sie immer noch keine Threads zum Teilen von Jobs. Für diese Art von Arbeit haben Sie zwei Threads, von denen einer die Kommunikation mit Node fortsetzt, während der andere die eigentliche Arbeit erledigt.

(2) Tatsächlich hat jeder Knotenprozess aus den gleichen Gründen, die ich in der ersten Fußnote erwähnt habe, mehrere Threads. Dies ist jedoch keineswegs so, als würden 1000 Threads ähnliche Arbeiten ausführen. Diese zusätzlichen Threads dienen dazu, E / A-Ereignisse zu akzeptieren und prozessübergreifende Nachrichten zu verarbeiten.

UPDATE (Als Antwort auf eine gute Frage in Kommentaren)

@ Mark, danke für die konstruktive Kritik. In Node's Paradigma sollten Sie niemals Funktionen haben, deren Verarbeitung zu lange dauert, es sei denn, alle anderen Aufrufe in der Warteschlange sind so konzipiert, dass sie nacheinander ausgeführt werden. Bei rechenintensiven Aufgaben stellen wir bei vollständiger Betrachtung des Bildes fest, dass es sich nicht um die Frage handelt, ob Threads oder Prozesse verwendet werden sollen. aber eine Frage von "Wie können wir diese Aufgaben in ausgewogener Weise in Unteraufgaben aufteilen, die wir parallel ausführen können, indem wir mehrere CPU-Kerne auf dem System verwenden?" Angenommen, wir verarbeiten 400 Videodateien auf einem System mit 8 Kernen. Wenn wir jeweils eine Datei verarbeiten möchten, benötigen wir ein System, das verschiedene Teile derselben Datei verarbeitet. In diesem Fall ist ein Multithread-Einzelprozesssystem möglicherweise einfacher zu erstellen und noch effizienter. Wir können Node weiterhin dafür verwenden, indem wir mehrere Prozesse ausführen und Nachrichten zwischen ihnen weitergeben, wenn eine gemeinsame Nutzung / Kommunikation des Status erforderlich ist. Wie ich bereits sagte, ist ein Multiprozess-Ansatz mit Nodesowie ein Multithread-Ansatz für diese Art von Aufgaben; aber nicht mehr als das. Wie ich bereits sagte, ist die Situation, in der Node glänzt, wenn diese Aufgaben als Eingabe aus mehreren Quellen in das System eingehen, da das gleichzeitige Aufrechterhalten vieler Verbindungen in Node im Vergleich zu einem Thread pro Verbindung oder einem Prozess pro Verbindung viel leichter ist System.

Wie für setTimeout(...,0)Anrufe; Manchmal kann es erforderlich sein, während einer zeitaufwändigen Aufgabe eine Pause einzulegen, damit Anrufe in der Warteschlange ihren Anteil an der Verarbeitung haben. Durch das Aufteilen von Aufgaben auf verschiedene Arten können Sie sich diese ersparen. Trotzdem ist dies kein wirklicher Hack, sondern nur die Art und Weise, wie Ereigniswarteschlangen funktionieren. Die Verwendung process.nextTickfür dieses Ziel ist auch viel besser, da bei der Verwendung setTimeoutBerechnungen und Überprüfungen der verstrichenen Zeit erforderlich sind, während dies process.nextTickeinfach das ist, was wir wirklich wollen: "Hey Aufgabe, gehen Sie zurück zum Ende der Warteschlange, Sie haben Ihren Anteil verwendet! ""


9
Tolle! Verdammt erstaunlich! Ich fand es toll, wie Sie diese Frage beantwortet haben! :)
Parth Thakkar

48
Klar :) Ich kann wirklich nicht glauben, dass es extrem gemeine Leute gibt, die diesen Antwortartikel abstimmen! Der Fragesteller nennt es "Verdammt erstaunlich!" und ein Buchautor bietet mir an, auf seiner Website zu schreiben, nachdem ich dies gesehen habe; aber einige Genies da draußen stimmen es ab. Warum teilen Sie nicht Ihre helle intellektuelle Qualität und kommentieren sie, anstatt gemein und heimlich abzustimmen? Warum stört dich etwas Schönes so sehr? Warum möchten Sie verhindern, dass etwas Nützliches andere Menschen erreicht, die wirklich davon profitieren können?
Hasanyasin

9
Dies ist keine völlig faire Antwort. Was ist mit rechenintensiven Aufgaben, bei denen wir unseren Funktionsaufruf nicht "schnell beenden" können? Ich glaube, einige Leute verwenden einige setTimeout(...,0)Hacks dafür, aber die Verwendung eines separaten Threads in diesem Szenario wäre sicherlich besser?
Mpen

3
@hasanyasin Dies ist die schönste Erklärung auf Knoten, die ich bisher gefunden habe! :)
Venemo

7
@Mark Wenn es so rechenintensiv ist, gibt es im Allgemeinen Optionen / Module für Laufflächen- / Prozessarbeiter ... Im Allgemeinen verwende ich für diese Art von Dingen eine Nachrichtenwarteschlange und habe Arbeitsprozesse, die eine Aufgabe an einem erledigen Zeit aus der Warteschlange, und arbeiten Sie diese Aufgabe. Dies ermöglicht auch die Skalierung auf mehrere Server. In diesem Sinne verfügt Substack über viele Module, die auf die Bereitstellung und Skalierung ausgerichtet sind.
Tracker1

34

(Update 2016: Web-Mitarbeiter gehen in io.js - eine Node.js-Gabel Node.js v7 - siehe unten.)

(Update 2017: Web-Worker gehen nicht in Node.js v7 oder v8 - siehe unten.)

(Update 2018: Web - Arbeiter werden gehen in Node.js Knoten v10.5.0 - siehe weiter unten.)

Einige Klarstellungen

Nachdem ich die obigen Antworten gelesen habe, möchte ich darauf hinweisen, dass es in Web-Workern nichts gibt, was gegen die Philosophie von JavaScript im Allgemeinen und Node im Besonderen in Bezug auf Parallelität verstößt. (Wenn ja, würde es nicht einmal von der WHATWG diskutiert, geschweige denn in den Browsern implementiert).

Sie können sich einen Web-Worker als einen einfachen Microservice vorstellen, auf den asynchron zugegriffen wird. Es wird kein Status geteilt. Es bestehen keine Verriegelungsprobleme. Es gibt keine Blockierung. Es ist keine Synchronisation erforderlich. Genau wie bei der Verwendung eines RESTful-Dienstes aus Ihrem Node-Programm müssen Sie sich keine Sorgen machen, dass dieser jetzt "Multithread" ist, da sich der RESTful-Dienst nicht im selben Thread wie Ihre eigene Ereignisschleife befindet. Es ist nur ein separater Dienst, auf den Sie asynchron zugreifen, und darauf kommt es an.

Gleiches gilt für Web-Worker. Es ist nur eine API für die Kommunikation mit Code, der in einem völlig separaten Kontext ausgeführt wird. Ob es sich um einen anderen Thread, einen anderen Prozess, eine andere Gruppe, eine andere Zone, einen anderen Container oder einen anderen Computer handelt, ist aufgrund einer streng asynchronen, nicht blockierenden API völlig irrelevant. mit allen Daten als Wert übergeben.

Tatsächlich passen Web-Worker konzeptionell perfekt zu Node, das - wie viele Leute nicht wissen - im Übrigen ziemlich häufig Threads verwendet, und tatsächlich "läuft alles parallel außer Ihrem Code" - siehe:

Die Web-Worker müssen jedoch nicht einmal mithilfe von Threads implementiert werden. Sie können Prozesse, grüne Threads oder sogar RESTful-Services in der Cloud verwenden - solange die Web-Worker-API verwendet wird. Das Schöne an der Message-Passing-API mit Call-by-Value-Semantik ist, dass die zugrunde liegende Implementierung so gut wie irrelevant ist, da die Details des Parallelitätsmodells nicht offengelegt werden.

Eine Single-Threaded-Ereignisschleife ist perfekt für E / A-gebundene Operationen. Es funktioniert nicht so gut für CPU-gebundene Operationen, insbesondere für lange laufende. Dafür müssen wir mehr Prozesse erzeugen oder Threads verwenden. Das tragbare Verwalten untergeordneter Prozesse und der Kommunikation zwischen Prozessen kann sehr schwierig sein und wird häufig als Overkill für einfache Aufgaben angesehen. Die Verwendung von Threads bedeutet jedoch, dass Sperren und Synchronisierungsprobleme behoben werden müssen, die nur schwer richtig zu beheben sind.

Was oft empfohlen wird, ist, lang laufende CPU-gebundene Operationen in kleinere Aufgaben zu unterteilen (so etwas wie das Beispiel im Abschnitt "Ursprüngliche Antwort" meiner Antwort auf Speed ​​up setInterval ), aber es ist nicht immer praktisch und es werden nicht mehr verwendet als ein CPU-Kern.

Ich schreibe es, um die Kommentare zu verdeutlichen, die im Grunde besagten, dass Web-Worker für Browser und nicht für Server erstellt wurden (wobei vergessen wurde, dass über so ziemlich alles in JavaScript gesagt werden kann).

Knotenmodule

Es gibt nur wenige Module, die Web Worker zum Knoten hinzufügen sollen:

Ich habe keine davon verwendet, aber ich habe zwei kurze Beobachtungen, die relevant sein könnten: Ab März 2015 wurde Node-Webworker zuletzt vor 4 Jahren aktualisiert und Node-Webworker-Threads wurden zuletzt vor einem Monat aktualisiert. Außerdem sehe ich im Beispiel der Verwendung von Node-Webworker-Threads, dass Sie eine Funktion anstelle eines Dateinamens als Argument für den Worker-Konstruktor verwenden können, was subtile Probleme verursachen kann, wenn es mit Threads implementiert wird, die Speicher gemeinsam nutzen (es sei denn, die Funktionen werden nur für die .toString () -Methode verwendet und ansonsten in einer anderen Umgebung kompiliert. In diesem Fall kann es in Ordnung sein - ich muss mich eingehender damit befassen und nur meine Beobachtungen hier teilen.

Wenn es ein anderes relevantes Projekt gibt, das die Web-Worker-API in Node implementiert, hinterlassen Sie bitte einen Kommentar.

Update 1

Ich wusste es zum Zeitpunkt des Schreibens noch nicht, aber übrigens einen Tag bevor ich diese Antwort schrieb, wurden Web Worker zu io.js hinzugefügt .

( io.js ist eine Abzweigung von Node.js - siehe: Warum io.js beschlossen hat, Node.js , ein InfoWorld-Interview mit Mikeal Rogers, für weitere Informationen aufzuteilen.)

Dies beweist nicht nur, dass es in Web-Workern nichts gibt, was gegen die Philosophie von JavaScript im Allgemeinen und Node im Besonderen in Bezug auf Parallelität verstößt, sondern es kann auch dazu führen, dass Web-Worker ein erstklassiger Bürger in serverseitigem JavaScript wie io sind. js (und möglicherweise Node.js in der Zukunft) so wie es bereits in clientseitigem JavaScript in allen modernen Browsern vorhanden ist .

Update 2

In Update 1 und meinem Tweet bezog ich mich auf io.js Pull-Anfrage Nr. 1159, die jetzt zu Knoten PR Nr. 1159 umleitet, der am 8. Juli geschlossen und durch Knoten PR Nr. 2133 ersetzt wurde - der noch offen ist. Unter diesen Pull-Anfragen finden einige Diskussionen statt, die möglicherweise aktuellere Informationen zum Status von Web-Workern in io.js / Node.js enthalten.

Update 3

Neueste Informationen - danke an NiCk Newman für die Veröffentlichung in den Kommentaren: Da sind die Mitarbeiter: Erstes Implementierungs- Commit von Petka Antonov vom 6. September 2015, das in diesem Baum heruntergeladen und ausprobiert werden kann . Siehe Kommentare von NiCk Newman für Details.

Update 4

Ab Mai 2016 waren die letzten Kommentare zu den noch offenen PR # 2133 - Arbeitern: Die erste Implementierung war 3 Monate alt. Am 30. Mai bat mich Matheus Moreira, in den Kommentaren unten ein Update zu dieser Antwort zu veröffentlichen, und er fragte in den PR-Kommentaren nach dem aktuellen Status dieser Funktion .

Die ersten Antworten in der PR-Diskussion waren skeptisch, aber später schrieb Ben Noordhuis , dass "das Zusammenführen in der einen oder anderen Form auf meiner Aufgabenliste für Version 7 steht".

Alle anderen Kommentare schienen dem zuzustimmen, und ab Juli 2016 scheint es so sollten Web Worker in der nächsten Version von Node , Version 7.0, verfügbar sein, die voraussichtlich im Oktober 2016 veröffentlicht wird (nicht unbedingt in Form dieser genauen PR).

Vielen Dank an Matheus Moreira für den Hinweis in den Kommentaren und die Wiederbelebung der Diskussion auf GitHub.

Update 5

Ab Juli 2016 gab es nur wenige Module auf npm, die zuvor nicht verfügbar waren. Eine vollständige Liste der relevanten Module finden Sie unter npm nach Workern, Web-Workern usw. Wenn etwas Besonderes für Sie funktioniert oder nicht, senden Sie bitte eine Kommentar.

Update 6

Stand Januar 2017 es unwahrscheinlich, dass Web-Worker in Node.js zusammengeführt werden.

Die Pull-Anfrage # 2133 Arbeiter: Die erste Implementierung durch Petka Antonov vom 8. Juli 2015 wurde endgültig abgeschlossen am 11. Dezember 2016 von Ben Noordhuis Er kommentierte, dass "Multithreading-Unterstützung zu viele neue Fehlermodi für nicht genügend Nutzen hinzufügt" und "wir kann dies auch mit traditionelleren Mitteln wie Shared Memory und effizienterer Serialisierung erreichen. "

Weitere Informationen finden Sie in den Kommentaren zum PR 2133 auf GitHub.

Nochmals vielen Dank an Matheus Moreira für den Hinweis in den Kommentaren.

Update 6

Ich freue mich, Ihnen mitteilen zu können, dass vor einigen Tagen im Juni 2018 Web-Mitarbeiter in Node 10.5.0 als experimentelle Funktion mit der --experimental-workerFlagge aktiviert wurden .

Weitere Informationen finden Sie unter:

🎉🎉🎉 Endlich! Ich kann das 7. Update meiner 3 Jahre alten Stack Overflow-Antwort vornehmen, in der ich argumentiere, dass das Threading von Web-Workern nicht gegen die Node-Philosophie verstößt, nur diesmal, dass wir es endlich verstanden haben! 😜👍


1
@ NiCkNewman Danke. Ich sehe, dass die ursprüngliche Pull-Anfrage in io.js jetzt geschlossen und durch eine andere ersetzt wird - mit einigen Diskussionen in den Kommentaren zu Pull-Anfragen auf GitHub können Sie dort möglicherweise einige Informationen finden. Siehe: Update 2 in meiner Antwort.
rsp

1
Ja, es sieht so aus, als hätten sie gerade das letzte libuv-Problem behoben. Ich frage mich, wann ich das Modul in die Hände bekommen kann. Ich kann es kaum erwarten! Vielen Dank, dass Sie uns auf dem Laufenden gehalten haben ~ Bearbeiten: Wurde gerade initialisiert: github.com/petkaantonov/io.js/commit/… Los geht's!
NiCk Newman

1
Ja, es ist live. (Noch nicht offiziell implementiert), aber Sie können die Quelle hier herunterladen: github.com/petkaantonov/io.js/tree/… und kompilieren, wenn Sie es testen möchten! Ich mache es jetzt ~
NiCk Newman

1
@NiCkNewman Danke für die neuen Infos - ich habe sie der Antwort hinzugefügt.
rsp

1
Können Sie uns bitte den Status der Node.js- workersImplementierung mitteilen ? Die neuesten Kommentare in PR # 2133 stammen aus dem Februar. Die Entwickler sind anscheinend auf ein Problem gestoßen und es gibt keine Kommentare, die darauf hinweisen, dass es gelöst wurde.
Matheus Moreira

8

Ich komme aus der alten Denkschule, in der wir Multithreading verwendet haben, um Software schnell zu machen. Seit 3 ​​Jahren benutze ich Node.js und einen großen Unterstützer davon. Wie Hasanyasin ausführlich erklärt hat, wie der Knoten funktioniert und das Konzept der asynchronen Funktionalität. Aber lassen Sie mich hier einige Dinge hinzufügen.

Früher haben wir mit einzelnen Kernen und niedrigeren Taktraten verschiedene Möglichkeiten ausprobiert, um Software schnell und parallel arbeiten zu lassen. In DOS-Tagen führen wir jeweils ein Programm aus. Als in Windows haben wir begonnen, mehrere Anwendungen (Prozesse) zusammen auszuführen. Konzepte wie präventiv und nicht präventiv (oder kooperativ) wurden getestet. Wir wissen jetzt, dass Präventiv die Antwort für eine bessere Mehrfachverarbeitungsaufgabe auf Single-Core-Computern war. Es folgten die Konzepte von Prozessen / Aufgaben und Kontextwechsel. Als das Konzept des Threads, um die Belastung durch Prozesskontextwechsel weiter zu reduzieren. Der Faden wurde als leichte Alternative zum Laichen neuer Prozesse geprägt.

Ob es Ihnen gefällt oder nicht, Signal-Thread oder nicht Multi-Core oder Single-Core, Ihre Prozesse werden vom Betriebssystem vorab geprüft und zeitlich getrennt.

Nodejs ist ein einzelner Prozess und bietet einen asynchronen Mechanismus. Hier werden Jobs an ein unterliegendes Betriebssystem gesendet, um Aufgaben auszuführen, während wir in einer Ereignisschleife auf den Abschluss der Aufgabe warten. Sobald wir ein grünes Signal vom Betriebssystem erhalten, führen wir alles aus, was wir tun müssen. In gewisser Weise handelt es sich um kooperatives / nicht präemptives Multitasking. Daher sollten wir die Ereignisschleife niemals für einen sehr langen Zeitraum blockieren, da wir sonst unsere Anwendung sehr schnell beeinträchtigen.
Wenn es also jemals eine Aufgabe gibt, die in der Natur blockiert oder sehr zeitaufwändig ist, müssen wir sie in die präventive Welt von Betriebssystemen und Threads verzweigen. Es gibt gute Beispiele dafür in der libuv-Dokumentation . Wenn Sie die Dokumentation weiter lesen, werden Sie feststellen, dass FileI / O in Threads in node.js behandelt wird .

Also erstens geht es um das Design unserer Software. Zweitens findet immer eine Kontextumschaltung statt, egal was sie Ihnen sagen. Thread sind aus einem bestimmten Grund vorhanden und immer noch vorhanden. Der Grund dafür ist, dass sie schneller zwischen den Prozessen wechseln können.

Unter der Haube in node.js sind alle C ++ und Threads. Und Node bietet eine C ++ - Möglichkeit, seine Funktionalität zu erweitern und die Geschwindigkeit zu erhöhen, indem Threads dort verwendet werden, wo sie ein Muss sind, dh Aufgaben wie das Lesen von einer Quelle, die in eine Quelle schreibt, die Analyse großer Datenmengen usw. werden blockiert.

Ich weiß, dass die Antwort von hasanyasin die akzeptierte ist, aber für mich gibt es Threads, egal was Sie sagen oder wie Sie sie hinter Skripten verstecken. Zweitens teilt niemand die Dinge nur in Threads auf, nur um die Geschwindigkeit zu erhöhen, die hauptsächlich zum Blockieren von Aufgaben verwendet wird. Und Threads befinden sich im Backbone von Node.js, sodass Multithreading korrekt ist, bevor das Bashing vollständig ausgeführt wird. Außerdem unterscheiden sich Threads von Prozessen, und die Einschränkung, dass Knotenprozesse pro Kern vorhanden sind, gilt nicht genau für die Anzahl der Threads. Threads sind wie Unteraufgaben eines Prozesses. Tatsächlich werden Threads nicht in Ihrem Windows Task-Manager oder Linux-Top-Befehl angezeigt. wieder sind sie mehr wenig gewicht als prozesse


Asynchroner Code ist keine große Innovation (tatsächlich haben wir ihn seit Jahrzehnten) und Multithreading ist keine veraltete Technologie, die ersetzt werden muss. Es sind verschiedene Werkzeuge mit unterschiedlichen Kompromissen, und tatsächlich können sie sogar recht gut kombiniert werden. Jedes Mal, wenn Sie Node-Cluster ausführen, führen Sie tatsächlich mehrere "Threads" aus (Prozesse in diesem Fall, aber dasselbe könnte mit Threads erreicht werden und noch leichter sein). Oder nehmen Sie Erlang oder Go, die Tausende von grünen Fäden ziehen können ...
Hejazzman

Ich denke, der wichtigste Punkt, den wir vermissen, ist, dass der Prozess unter dem Betriebssystem immer präventiv durchgeführt wird, um Fairness zu gewährleisten. Auch mit Multi-Prozessoren können Sie tatsächlich parallelen Code ausführen, aber selbst dann haben Sie Vorrang. Asynchrone Arbeit wird auch vom Betriebssystem in einigen Prozessen ausgeführt.
Limplash

4

Ich bin nicht sicher, ob Webworker in diesem Fall relevant sind. Sie sind clientseitige Technologien (werden im Browser ausgeführt), während node.js auf dem Server ausgeführt wird. Soweit ich weiß, blockieren Fasern auch, dh sie sind freiwilliges Multitasking, sodass Sie sie verwenden können, aber Kontextwechsel selbst verwalten sollten yield. Threads könnten tatsächlich das sein, was Sie brauchen, aber ich weiß nicht, wie ausgereift sie in node.js sind.


3
Nur zu Ihrer Information, Webworker wurden (teilweise) auf node.js angepasst. Und sind als node-workersPaket erhältlich. Schauen Sie sich das an: github.com/cramforce/node-worker
Parth Thakkar

Gut zu wissen, danke. Dokumente sind jedoch sehr selten. Ich habe keine Ahnung, ob sie in einem separaten Thread, Prozess oder einfach im selben Prozess ausgeführt werden, und ich habe keine Zeit, mich mit dem Code zu befassen, daher habe ich keine Ahnung, ob dies der Fall ist Arbeit für Ihren Fall.
Lanzz

@ParthThakkar: Dieses Projekt wurde seit 3 ​​Jahren nicht mehr berührt (2 als Sie gepostet haben) und hat es nicht über 0.0.1 hinaus geschafft.
Mpen

@ Mark: Der Grund für meine Unwissenheit darüber ist, dass ich noch kein professioneller Programmierer bin. Ich bin nicht mal an einer Universität. Ich bin immer noch ein High School-Stipendiat, der immer wieder über Programmierung liest - neben der Verwaltung der Schularbeit. Daher ist es mir nicht aus der Ferne möglich, über all diese Probleme Bescheid zu wissen. Ich habe gerade gepostet, was ich wusste ...
Parth Thakkar

@ Mark: Obwohl es nett von Ihnen war, darauf über die Geschichte des Projekts hinzuweisen. Solche Dinge werden in meinen zukünftigen Antworten behandelt !! :)
Parth Thakkar

3

worker_threadswurde implementiert und hinter einer Flagge in versendet node@10.5.0. Es ist noch eine erste Implementierung und es sind weitere Anstrengungen erforderlich, um sie in zukünftigen Versionen effizienter zu gestalten. Es lohnt sich, es spätestens einmal auszuprobieren node.


2

Nach Meinung vieler Node-Entwickler ist einer der besten Teile von Node seine Single-Thread-Natur. Threads bringen eine ganze Reihe von Schwierigkeiten mit gemeinsam genutzten Ressourcen mit sich, die Node vollständig vermeidet, indem er nur nicht blockierende E / A-Vorgänge ausführt.

Das heißt nicht, dass Node auf einen einzelnen Thread beschränkt ist. Es ist nur so, dass sich die Methode zum Abrufen der Thread-Parallelität von der gesuchten unterscheidet. Die Standardmethode für den Umgang mit Threads ist das Cluster- Modul, das standardmäßig mit Node selbst geliefert wird. Es ist ein einfacherer Ansatz für Threads, als sie manuell in Ihrem Code zu behandeln.

Für die asynchrone Programmierung in Ihrem Code (wie in Vermeidung verschachtelter Rückrufpyramiden) ist die Komponente [Future] in der Fibre- Bibliothek eine gute Wahl. Ich würde auch vorschlagen, dass Sie sich Asyncblock ansehen, das auf Fasern basiert. Fasern sind nett, weil sie es Ihnen ermöglichen, Rückrufe zu verbergen, indem Sie den Stapel duplizieren und dann bei Bedarf zwischen Stapeln auf einem einzelnen Thread wechseln. Spart Ihnen den Ärger mit echten Fäden und bietet Ihnen gleichzeitig die Vorteile. Der Nachteil ist, dass Stapelspuren bei der Verwendung von Fasern etwas seltsam werden können, aber sie sind nicht schlecht.

Wenn Sie sich nicht um asynchrone Dinge kümmern müssen und mehr daran interessiert sind, viel zu verarbeiten, ohne zu blockieren, ist ein einfacher Aufruf von process.nextTick (Rückruf) von Zeit zu Zeit alles, was Sie brauchen.


Nun, Ihr Vorschlag - über Cluster - war das, worüber ich ursprünglich nachgedacht habe. Das Problem dabei ist jedoch der Overhead: Jedes Mal, wenn ein neuer Prozess gegabelt wird, muss eine neue Instanz von Version 8 initialisiert werden (~ 30 ms, 10 MB). Sie können also nicht viele davon erstellen. Dies wird direkt aus den Knotendokumenten übernommen: Diese untergeordneten Knoten (über child_processes) sind noch ganz neue Instanzen von V8. Angenommen, mindestens 30 ms Start und 10 MB Speicher für jeden neuen Knoten. Das heißt, Sie können nicht viele tausend davon erstellen.
Parth Thakkar

1
Dies ist genau die Idee des Clusters. Sie führen einen Worker pro CPU-Kern aus. Mehr ist höchstwahrscheinlich nicht notwendig. Selbst CPU-intensive Aufgaben funktionieren problemlos mit einem asynchronen Stil. Wenn Sie jedoch wirklich vollständige Threads benötigen, sollten Sie wahrscheinlich in Betracht ziehen, vollständig auf ein anderes Server-Backend zu wechseln.
genericdave

1

Vielleicht helfen weitere Informationen darüber, welche Aufgaben Sie ausführen. Warum sollten Sie (wie Sie in Ihrem Kommentar zur Antwort von genericdave erwähnt haben) viele tausend davon erstellen müssen? Die übliche Vorgehensweise in Node besteht darin, einen Arbeitsprozess (mit Fork oder einer anderen Methode) zu starten, der immer ausgeführt wird und über Nachrichten kommuniziert werden kann. Mit anderen Worten, starten Sie nicht jedes Mal einen neuen Mitarbeiter, wenn Sie die von Ihnen ausgeführte Aufgabe ausführen müssen, sondern senden Sie einfach eine Nachricht an den bereits ausgeführten Mitarbeiter und erhalten Sie eine Antwort, wenn diese erledigt ist. Ehrlich gesagt kann ich nicht sehen, dass das Starten von vielen tausend tatsächlichen Threads auch sehr effizient wäre. Sie sind immer noch durch Ihre CPUs eingeschränkt.

Nachdem ich das alles gesagt habe, habe ich in letzter Zeit viel mit Hook.io gearbeitet, was für diese Art des Abladens von Aufgaben in andere Prozesse sehr gut zu funktionieren scheint. Vielleicht kann es das erreichen, was Sie brauchen.

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.