it-swarm.com.de

Was sind die Nachteile einer Multithread-JavaScript-Laufzeitimplementierung?

Ich habe in der letzten Woche an einer Multithread-JavaScript-Laufzeitimplementierung gearbeitet. Ich habe einen Proof of Concept in C++ mit JavaScriptCore und Boost erstellt.

Die Architektur ist einfach: Wenn die Laufzeit die Auswertung des Hauptskripts abgeschlossen hat, wird sie gestartet und tritt einem Thread-Pool bei, der beginnt, Aufgaben aus einer Warteschlange mit gemeinsam genutzter Priorität auszuwählen. Wenn zwei Aufgaben gleichzeitig versuchen, auf eine Variable zuzugreifen, wird sie als atomar markiert und sie kämpfen um den Zugriff .

(Working multithreaded node.js runtime

Das Problem ist, dass ich, wenn ich dieses Design einem JavaScript-Programmierer zeige, extrem negatives Feedback bekomme und keine Ahnung habe, warum. Selbst privat sagen alle, dass JavaScript als Single-Thread gedacht ist, dass vorhandene Bibliotheken neu geschrieben werden müssten und dass Gremlins jedes Lebewesen hervorbringen und essen würden, wenn ich weiter daran arbeite.

Ich hatte ursprünglich auch eine native Coroutine-Implementierung (unter Verwendung von Boost-Kontexten), aber ich musste sie fallen lassen (JavaScriptCore ist pedantisch in Bezug auf den Stack), und ich wollte ihren Zorn nicht riskieren, also habe ich mich dagegen entschieden, sie zu erwähnen.

Was denken Sie? Ist JavaScript als Single-Thread gedacht und sollte es in Ruhe gelassen werden? Warum ist jeder gegen die Idee einer gleichzeitigen JavaScript-Laufzeit?

Edit: Das Projekt ist jetzt auf GitHub , experimentiere selbst damit und lass mich wissen, was du denkst.

Das Folgende ist ein Bild von Versprechungen, die auf allen CPU-Kernen parallel ohne Konkurrenz ausgeführt werden:

(Running promises concurrently.

51
voodooattack

1) Multithreading ist extrem schwierig, und leider impliziert die Art und Weise, wie Sie diese Idee bisher präsentiert haben, dass Sie stark unterschätzen, wie schwierig es ist.

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 korrigieren und durchführen können. Bestimmtes:

wenn zwei Tasks gleichzeitig versuchen, auf eine Variable zuzugreifen, wird diese als atomar markiert und sie kämpfen um den Zugriff.
...
Ich stimme zu, dass atomare Variablen nicht alles lösen werden, aber die Arbeit an einer Lösung für das Synchronisationsproblem ist mein nächstes Ziel.

Das Hinzufügen von Threads zu Javascript ohne eine "Lösung für das Synchronisationsproblem" wäre wie das Hinzufügen von Ganzzahlen zu Javascript ohne eine "Lösung für das Additionsproblem". Es ist so grundlegend für die Natur des Problems, dass es im Grunde keinen Sinn macht, darüber zu diskutieren, ob es sich lohnt, Multithreading hinzuzufügen, ohne eine bestimmte Lösung im Auge zu haben, egal wie sehr wir es wollen.

Darüber hinaus ist es wahrscheinlich, dass ein Multithread-Programm eine Leistung von schlechter erzielt als sein Gegenstück mit Singlethread, was es noch wichtiger macht, die Leistung mit realistischeren Programmen zu testen und zu prüfen, ob Sie dies tun gewinnen etwas oder nicht.

Mir ist auch nicht klar, ob Sie versuchen, Threads vor dem Programmierer node.js verborgen zu halten, oder ob Sie sie irgendwann verfügbar machen möchten, um effektiv einen neuen Javascript-Dialekt für die Multithread-Programmierung zu erstellen. Beide Optionen sind möglicherweise interessant, aber es scheint, als hätten Sie noch nicht einmal entschieden, welche Sie anstreben.

Im Moment bitten Sie Programmierer daher, den Wechsel von einer Singlethread-Umgebung zu einer brandneuen Multithread-Umgebung in Betracht zu ziehen, 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 aufweist.

Das ist wahrscheinlich der Grund, warum die Leute dich nicht ernst nehmen.

2) Die Einfachheit und Robustheit der Einzelereignisschleife ist ein riesiger Vorteil.

Javascript-Programmierer wissen, dass die Javascript-Sprache vor Rennbedingungen und anderen äußerst heimtückischen Fehlern "sicher" ist, die alle wirklich Multithread-Programme plagen. Die Tatsache, dass sie starke Argumente brauchen, um sie davon zu überzeugen, aufzugeben, dass Sicherheit sie nicht verschlossen, sondern verantwortlich macht.

Wenn Sie diese Sicherheit nicht irgendwie beibehalten können, ist es für jeden, der zu einem Multithread-Knoten wechseln möchte, wahrscheinlich besser, zu einer Sprache wie Go zu wechseln, die von Grund auf für Multithread-Anwendungen entwickelt wurde.

3) Javascript unterstützt bereits "Hintergrund-Threads" (WebWorkers) und asynchrone Programmierung, ohne die Thread-Verwaltung direkt dem Programmierer zur Verfügung zu stellen.

Diese Funktionen lösen bereits viele der gängigen Anwendungsfälle, die Javascript-Programmierer in der realen Welt betreffen, ohne die Sicherheit der einzelnen Ereignisschleife aufzugeben.

Haben Sie spezielle Anwendungsfälle im Sinn, die diese Funktionen nicht lösen und für die Javascript-Programmierer eine Lösung wünschen? In diesem Fall ist es eine gute Idee, Ihre Multithread-node.js im Kontext dieses speziellen Anwendungsfalls zu präsentieren.


P.S. Was würde me davon überzeugen, zu einer Multithread-Implementierung von node.js zu wechseln?

Schreiben Sie ein nicht triviales Programm in Javascript/node.js, von dem Sie glauben, dass es von echtem Multithreading profitieren würde. Führen Sie Leistungstests für dieses Beispielprogramm im normalen Knoten und auf Ihrem Multithread-Knoten durch. Zeigen Sie mir, dass Ihre Version die Laufzeitleistung, Reaktionsfähigkeit und 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.

72
Ixrec

Hier nur raten, 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 'eine Variable' im allgemeinen Fall nicht ausreicht, um den Umfang einer Sperre zu bestimmen. Stellen Sie sich zum Beispiel vor, wir haben eine Invariante, die a+b = 0 (Bankguthaben mit zwei Konten). Die beiden folgenden Funktionen stellen sicher, dass die Invariante immer gehalten wird am Ende jeder Funktion (die Ausführungseinheit in Single-Threaded-JS).

function withdraw(v) {
  a -= v;
  b += v;
}
function deposit(v) {
  b -= v;
  a += v;
}

Was passiert nun in Ihrer Multithread-Welt, wenn zwei Threads withdraw und deposit gleichzeitig ausführen? 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 können zwei Variablen nicht gleichzeitig sperren, wenn Ihre Invariante dies tut verletzt werden.)


BEARBEITEN: Wenn Ihr Code semantisch dem Go-Code unter https://Gist.github.com/thriqon/f94c10a45b7e0bf656781b0f4a07292a entspricht, ist mein Kommentar korrekt ;-)

16
thriqon

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 Design-Mythologie von JavaScript ist.

Ob es richtig ist, ist eine andere Frage, aber ich denke, es hatte einen großen Einfluss darauf, wie die JavaScript-Community über Parallelität denkt.

15
Erik Pukinskis

Atomic Access 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 (beispielsweise beim Hinzufügen einer Eigenschaft zu einem Objekt) oder beim Sortieren eines globalen Arrays. Während dieser Zeit können Sie keinem anderen Thread den Zugriff auf die Variable erlauben. Dies bedeutet im Grunde, dass Sie die gesamten Lese-, Aktualisierungs- und Schreibzyklen erkennen und diese sperren müssen. Wenn das Update nicht trivial ist, wird das Problemgebiet gestoppt.

Javascript wurde von Anfang an mit einem Thread und einer Sandbox versehen, und der gesamte Code wurde 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 Multi-Thread-Pitfals umgehen sollen.

8
ratchet freak

Wird Ihr Ansatz die Leistung erheblich verbessern?

Zweifelhaft. Sie müssen das wirklich beweisen.

Wird Ihr Ansatz das Schreiben von Code einfacher/schneller machen?

Definitiv nicht, Multithread-Code ist um ein Vielfaches schwieriger zu finden als Single-Threaded-Code.

Wird Ihr Ansatz robuster sein?

Deadlocks, Rennbedingungen usw. sind ein Albtraum, den es zu beheben gilt.

6
Phil Wright

Bei Ihrer Implementierung geht es nicht nur um die Einführung von Parallelität, sondern auch um die Einführung einer bestimmten Methode zur Implementierung von Parallelität, d. H. Parallelität durch gemeinsam genutzten veränderlichen Status. Im Laufe der Geschichte haben 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 gemeinsamen Parallelität von veränderlichen Zuständen zusammenarbeiten, aber der eigentliche Test eines Mechanismus ist nicht, 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. Sie entwickelt sich im Laufe der Zeit weiter. Wenn ein Mechanismus oder Konzept die Entwicklung der Software nicht bewältigen kann, führt dies nur zu neuen Problemen, und genau das ist es Welche Geschichte hat uns über die gemeinsame Parallelität des veränderlichen Speichers gelehrt?.

Sie können sich andere Modelle der Parallelität ansehen (z. B. Nachrichtenübermittlung), um herauszufinden, welche Vorteile diese Modelle bieten.

2
Ankur

Dies ist erforderlich. Das Fehlen eines Parallelitätsmechanismus auf niedriger Ebene in Knoten js schränkt seine Anwendungen in Bereichen wie Mathematik und Bioinformatik usw. ein. Außerdem widerspricht die Parallelität mit Threads nicht unbedingt dem im Knoten verwendeten Standard-Parallelitätsmodell. Es gibt bekannte Semantiken für das Threading in einer Umgebung mit einer Hauptereignisschleife, wie z. B. UI-Frameworks (und NodeJs), und diese sind in den meisten Situationen, in denen sie noch gültige Verwendungszwecke haben, definitiv zu komplex.

Sicher, Ihre durchschnittliche Web-App benötigt keine Threads, aber versuchen Sie, etwas weniger Konventionelles zu tun, und das Fehlen eines soliden Parallelitätsprimitivs mit niedrigem Pegel wird Sie schnell zu etwas anderem führen, das es bietet.

1
dryajov

Ich glaube wirklich, dass es eine andere und kraftvolle Idee ist. Sie gehen gegen Glaubenssysteme. Sachen werden durch Netzwerkeffekte nicht aufgrund von Verdiensten akzeptiert oder populär. Auch will sich niemand an einen neuen Stack anpassen. Menschen lehnen automatisch zu unterschiedliche Dinge ab.

Wenn Sie einen Weg finden, es zu einem regulären npm-Modul zu machen, was unwahrscheinlich klingt, können einige Leute es verwenden.

0
Jason Livesay