Ich habe in der vergangenen Woche an einer JavaScript-Laufzeitimplementierung mit mehreren Threads gearbeitet. Ich habe einen in C ++ mit JavaScriptCore und Boost erstellten Proof of Concept.
Die Architektur ist einfach: Wenn die Laufzeit die Auswertung des von ihr gestarteten Hauptskripts beendet und sich einem Thread-Pool anschließt, der Aufgaben aus einer gemeinsam genutzten Prioritätswarteschlange auswählt, werden zwei Aufgaben, die versuchen, gleichzeitig auf eine Variable zuzugreifen, als atomar gekennzeichnet und konkurrieren um den Zugriff .
Das Problem ist, dass ich, wenn ich dieses Design einem JavaScript-Programmierer zeige, äußerst negatives Feedback bekomme und keine Ahnung habe, warum. Selbst privat sagen sie alle, dass JavaScript Single-Threading sein soll, dass vorhandene Bibliotheken neu geschrieben werden müssten und dass Gremlins jedes Lebewesen laichen und fressen werden, wenn ich weiter daran arbeite.
Ursprünglich hatte ich auch eine native Coroutine-Implementierung (unter Verwendung von Boost-Kontexten), aber ich musste darauf verzichten (JavaScriptCore ist pedantisch in Bezug auf den Stack), und ich wollte ihren Zorn nicht riskieren, also habe ich mich dagegen entschieden, es zu erwähnen.
Was denkst du? Ist JavaScript als Singlethread gedacht und sollte es in Ruhe gelassen werden? Warum ist jeder gegen die Idee einer gleichzeitigen JavaScript-Laufzeit?
Bearbeiten: Das Projekt ist jetzt auf GitHub , experimentieren Sie selbst und lassen Sie mich wissen, was Sie denken.
Das Folgende ist ein Bild von Versprechungen, die auf allen CPU-Kernen ohne Konkurrenz parallel ausgeführt werden:
quelle
Antworten:
1) Multithreading ist extrem schwierig, und leider impliziert die Art und Weise, wie Sie diese Idee bisher präsentiert haben, dass Sie die Schwierigkeit stark unterschätzen.
Im Moment klingt es so, als würden Sie der Sprache einfach "Threads hinzufügen" und sich Gedanken darüber machen, wie Sie sie später korrekt und performant machen können. Speziell:
Das Hinzufügen von Threads zu Javascript ohne "Lösung für das Synchronisationsproblem" entspricht dem Hinzufügen von Ganzzahlen zu Javascript ohne "Lösung für das Additionsproblem". Es ist so grundlegend für die Natur des Problems, dass es im Grunde keinen Grund gibt, darüber zu diskutieren, ob Multithreading ohne eine bestimmte Lösung hinzugefügt werden sollte, egal wie dringend wir es wollen.
Wenn Sie alle Variablen atomar machen, ist die Leistung eines Multithread-Programms wahrscheinlich schlechter als die eines Singlethread-Programms. Umso wichtiger ist es, die Leistung in realistischeren Programmen zu testen und festzustellen, ob Sie etwas gewinnen oder nicht.
Mir ist auch nicht klar, ob Sie versuchen, Threads vor dem Programmierer von node.js zu verbergen, oder ob Sie sie irgendwann verfügbar machen möchten, um effektiv einen neuen Dialekt von Javascript für Multithread-Programmierung zu erstellen. Beide Optionen sind möglicherweise interessant, aber es scheint, als hätten Sie sich noch nicht einmal entschieden, welche Sie anstreben.
Im Moment bitten Sie Programmierer, in Erwägung zu ziehen, von einer Singlethread-Umgebung zu einer brandneuen Multithread-Umgebung zu wechseln, die keine Lösung für das Synchronisationsproblem und keine Beweise für eine Verbesserung der realen Leistung bietet und anscheinend keinen Plan zur Lösung dieser Probleme hat.
Das ist wahrscheinlich der Grund, warum die Leute dich nicht ernst nehmen.
2) Die Einfachheit und Robustheit der Einzelereignisschleife ist ein großer Vorteil.
Javascript-Programmierer wissen, dass die Javascript-Sprache vor den Rennbedingungen und anderen extrem heimtückischen Fehlern, die die gesamte Multithread-Programmierung plagen, "sicher" ist. Die Tatsache, dass sie starke Argumente brauchen, um davon zu überzeugen, dass Sicherheit aufgegeben werden muss, macht sie nicht verschlossen, sondern verantwortlich.
Sofern Sie diese Sicherheit nicht irgendwie aufrechterhalten können, ist es für alle, die auf einen Multithread-Node.js umsteigen möchten, wahrscheinlich besser, auf eine Sprache wie Go umzuschalten, die von Grund auf für Multithread-Anwendungen entwickelt wurde.
3) Javascript unterstützt bereits "Hintergrundthreads" (WebWorkers) und asynchrone Programmierung, ohne das Thread-Management direkt dem Programmierer zugänglich zu machen.
Diese Funktionen lösen bereits viele der üblichen Anwendungsfälle, die JavaScript-Programmierer in der realen Welt betreffen, ohne die Sicherheit der Einzelereignisschleife aufzugeben.
Haben Sie spezielle Anwendungsfälle, für die diese Funktionen keine Lösung bieten und für die Javascript-Programmierer eine Lösung suchen? In diesem Fall ist es eine gute Idee, die Datei node.js mit mehreren Threads im Kontext dieses speziellen Anwendungsfalls zu präsentieren.
PS Was würde mich überzeugen , auf eine Multithread-Implementierung von node.js umzusteigen?
Schreiben Sie ein nicht triviales Programm in Javascript / node.js, von dem Sie glauben, dass es von echtem Multithreading profitiert. Führen Sie Leistungstests für dieses Beispielprogramm auf dem normalen Knoten und Ihrem Multithread-Knoten durch. Zeigen Sie mir, dass Ihre Version die Laufzeitleistung, die Reaktionsfähigkeit und die Verwendung mehrerer Kerne erheblich verbessert, ohne dass Fehler oder Instabilitäten auftreten.
Sobald Sie das getan haben, werden Sie wahrscheinlich Leute sehen, die sich viel mehr für diese Idee interessieren.
quelle
Ich rate hier nur, um ein Problem in Ihrem Ansatz zu demonstrieren. Ich kann es nicht gegen die reale Implementierung testen, da es nirgendwo einen Link gibt ...
Ich würde sagen, das liegt daran, dass Invarianten nicht immer durch den Wert einer Variablen ausgedrückt werden und dass 'eine Variable' im allgemeinen Fall nicht ausreicht, um den Gültigkeitsbereich einer Sperre zu bestimmen. Stellen Sie sich zum Beispiel vor, wir haben eine Invariante
a+b = 0
(Kontostand einer Bank mit zwei Konten). Die beiden folgenden Funktionen stellen sicher, dass die Invariante immer am Ende jeder Funktion gehalten wird (die Ausführungseinheit in Single-Threaded-JS).Jetzt, in Ihrer multithreaded Welt, was passiert , wenn zwei Threads ausführen
withdraw
unddeposit
zugleich? Danke, Murphy ...(Möglicherweise haben Sie Code, der + = und - = speziell behandelt, aber das ist keine Hilfe. Irgendwann haben Sie einen lokalen Status in einer Funktion, und ohne die Möglichkeit, zwei Variablen gleichzeitig zu sperren, wird dies Ihre Invariante tun verletzt werden.)
BEARBEITEN: Wenn Ihr Code semantisch dem Go-Code unter https://gist.github.com/thriqon/f94c10a45b7e0bf656781b0f4a07292a entspricht , ist mein Kommentar korrekt ;-)
quelle
Vor ungefähr einem Jahrzehnt schrieb Brendan Eich (der Erfinder von JavaScript) einen Aufsatz mit dem Titel Threads Suck , der definitiv eines der wenigen kanonischen Dokumente der JavaScript-Designmythologie ist.
Ob es richtig ist, ist eine andere Frage, aber ich denke, es hat einen großen Einfluss darauf, wie die JavaScript-Community über Parallelität denkt.
quelle
Atomarer Zugriff führt nicht zu threadsicherem Verhalten.
Ein Beispiel ist, wenn eine globale Datenstruktur während einer Aktualisierung ungültig sein muss, z. B. beim erneuten Aufbereiten einer Hashmap (z. B. beim Hinzufügen einer Eigenschaft zu einem Objekt) oder beim Sortieren eines globalen Arrays. Während dieser Zeit können Sie keinem anderen Thread erlauben, auf die Variable zuzugreifen. Dies bedeutet im Grunde, dass Sie die gesamten Lese-Update-Schreibzyklen erkennen und darüber hinwegsperren müssen. Wenn das Update nicht trivial ist, führt dies dazu, dass das Problemgebiet gestoppt wird.
Javascript wurde von Anfang an mit einem einzigen Thread und einer Sandbox erstellt, und der gesamte Code wird unter Berücksichtigung dieser Annahmen geschrieben.
Dies hat einen großen Vorteil in Bezug auf isolierte Kontexte und das Ausführen von zwei separaten Kontexten in verschiedenen Threads. Ich meine auch, dass Leute, die Javascript schreiben, nicht wissen müssen, wie sie mit Rennbedingungen und verschiedenen anderen Multithread-Pitfals umgehen sollen.
quelle
Wird Ihr Ansatz die Leistung erheblich verbessern?
Zweifelhaft. Sie müssen das wirklich beweisen.
Wird Ihr Ansatz das Schreiben von Code erleichtern / beschleunigen?
Auf keinen Fall, Multithread-Code ist um ein Vielfaches schwieriger zu finden als Single-Thread-Code.
Wird Ihr Ansatz robuster sein?
Deadlocks, Rennbedingungen usw. sind ein Albtraum.
quelle
Bei Ihrer Implementierung geht es nicht nur um die Einführung der Parallelität, sondern auch um die Einführung einer bestimmten Methode zur Implementierung der Parallelität, dh der Parallelität nach gemeinsamem veränderlichen Status. Im Laufe der Geschichte haben die Menschen diese Art der Parallelität verwendet und dies hat zu vielen Arten von Problemen geführt. Natürlich können Sie einfache Programme erstellen, die perfekt mit der Verwendung von gemeinsam genutzten veränderlichen Zuständen zusammenarbeiten, aber der eigentliche Test eines Mechanismus ist nicht das, was er kann, sondern kann skaliert werden, wenn das Programm komplex wird und dem Programm immer mehr Funktionen hinzugefügt werden. Denken Sie daran, dass Software keine statische Sache ist, die Sie einmal erstellt haben und mit der Sie fertig sind, sondern sich im Laufe der Zeit weiterentwickelt und ob irgendein Mechanismus oder Konzept dies kann. '
Sie können sich auch andere Modelle der Parallelität ansehen (z. B. Nachrichtenübermittlung), um herauszufinden, welche Vorteile diese Modelle bieten.
quelle
Das ist nötig. Das Fehlen eines Nebenläufigkeitsmechanismus auf niedriger Ebene in Knoten js schränkt seine Anwendungen in Bereichen wie Mathematik und Bioinformatik usw. ein. Außerdem steht die Nebenläufigkeit mit Threads nicht notwendigerweise in Konflikt mit dem in Knoten verwendeten Standard-Gleichzeitigkeitsmodell. Es gibt wohlbekannte Semantiken für das Threading in einer Umgebung mit einer Hauptereignisschleife, wie z. B. UI-Frameworks (und Nodejs), und sie sind definitiv zu komplex für die meisten Situationen, in denen sie noch gültige Verwendungen haben.
Sicherlich erfordert Ihre durchschnittliche Web-App keine Threads, aber versuchen Sie, etwas weniger Konventionelles zu tun, und das Fehlen eines soliden Grundelements mit niedriger Nebenläufigkeit wird Sie schnell dazu bringen, etwas anderes zu finden, das dies anbietet.
quelle
Ich glaube wirklich, dass es eine andere und mächtige Idee ist. Du gehst gegen Glaubenssysteme. Sachen werden akzeptiert oder populär durch Netzwerkeffekte, die nicht auf dem Verdienst beruhen. Auch will sich niemand an einen neuen Stack anpassen. Menschen lehnen automatisch Dinge ab, die zu unterschiedlich sind.
Wenn Sie einen Weg finden, wie Sie es zu einem normalen npm-Modul machen können, was unwahrscheinlich klingt, werden Sie möglicherweise einige Leute dazu bringen, es zu benutzen.
quelle