it-swarm.com.de

Werden Mutexe in Javascript benötigt?

Ich habe diesen Link gesehen: Implementieren des gegenseitigen Ausschlusses in JavaScript . Andererseits habe ich gelesen, dass Javascript keine Threads enthält, aber was genau bedeutet das?

Wo können Ereignisse im Code unterbrochen werden, wenn sie auftreten?

Und wenn es in JS keine Threads gibt, muss ich Mutexe in JS verwenden oder nicht?

Insbesondere wundere ich mich über die Auswirkungen der Verwendung von Funktionen, die von setTimeout() und XmlHttpRequest 's onreadystatechange für global zugreifbare Variablen aufgerufen werden.

99
Ovesh

Javascript ist definiert als wiedereintretend Sprache, was bedeutet, dass dem Benutzer kein Threading angezeigt wird. Möglicherweise befinden sich Threads in der Implementierung. Funktionen wie setTimeout() und asynchrone Rückrufe müssen warten, bis die Skript-Engine in den Ruhezustand versetzt wurde, bevor sie ausgeführt werden können.

Das bedeutet, dass alles, was in einem Ereignis passiert, beendet sein muss, bevor das nächste Ereignis verarbeitet wird.

Abgesehen davon benötigen Sie möglicherweise einen Mutex, wenn Ihr Code eine Aktion ausführt, bei der erwartet wird, dass sich ein Wert zwischen dem Zeitpunkt, an dem das asynchrone Ereignis ausgelöst wurde, und dem Zeitpunkt, an dem der Rückruf aufgerufen wurde, nicht ändert.

Wenn Sie beispielsweise eine Datenstruktur haben, in der Sie auf eine Schaltfläche klicken und eine XmlHttpRequest senden, die einen Rückruf aufruft, der die Datenstruktur auf destruktive Weise ändert, und wenn Sie zwischen dem Zeitpunkt des Ereignisses eine andere Schaltfläche haben, die dieselbe Datenstruktur direkt ändert ausgelöst, und wenn der Rückruf ausgeführt wurde, hätte der Benutzer die Datenstruktur vor dem Rückruf anklicken und aktualisieren können, wodurch der Wert verloren gehen könnte.

Während Sie eine Race-Bedingung wie diese erstellen könnten, ist es sehr einfach, dies in Ihrem Code zu verhindern, da jede Funktion atomar ist. Es wäre eine Menge Arbeit und würde einige seltsame Codierungsmuster erfordern, um die Rennbedingungen tatsächlich zu schaffen.

95
William

Die Antworten auf diese Frage sind etwas veraltet, obwohl sie zu dem Zeitpunkt korrekt waren, als sie gegeben wurden. Und immer noch richtig, wenn Sie sich eine clientseitige Javascript-Anwendung ansehen, die KEINE Webworker verwendet.

Artikel zu Web-Workern:
Multithreading in Javascript mit Webworkern
Mozilla auf Webworkern

Dies zeigt deutlich, dass Javascript über Web-Worker Multithreading-Funktionen hat. Was die Frage betrifft, werden Mutexe in Javascript benötigt? Da bin ich mir nicht sicher. Aber dieser Stackoverflow-Beitrag scheint relevant zu sein:
Gegenseitiger Ausschluss für N asynchrone Threads

18
gorillatron

Wie @william darauf hinweist,

möglicherweise benötigen Sie einen Mutex, wenn Ihr Code eine Aktion ausführt, bei der erwartet wird, dass sich ein Wert zwischen dem Zeitpunkt, zu dem das asynchrone Ereignis ausgelöst wurde, und dem Zeitpunkt, zu dem der Rückruf aufgerufen wurde, nicht ändert.

Dies kann weiter verallgemeinert werden. Wenn Ihr Code eine Aufgabe erfüllt, bei der er die ausschließliche Kontrolle über eine Ressource erwartet, bis eine asynchrone Anforderung aufgelöst wird, benötigen Sie möglicherweise einen Mutex.

Ein einfaches Beispiel ist, wenn Sie eine Schaltfläche haben, die einen Ajax-Aufruf auslöst, um einen Datensatz im Back-End zu erstellen. Möglicherweise benötigen Sie ein bisschen Code, um sich davor zu schützen, dass zufriedene Benutzer wegklicken und dadurch mehrere Datensätze erstellen. Es gibt eine Reihe von Ansätzen für dieses Problem (z. B. Deaktivieren der Schaltfläche, Aktivieren bei erfolgreichem Ajax). Sie können auch ein einfaches Schloss verwenden:

var save_lock = false;
$('#save_button').click(function(){
    if(!save_lock){
        //lock
        save_lock=true;
        $.ajax({
            success:function()
                //unlock
                save_lock = false;  
            }
        });
    }
}

Ich bin mir nicht sicher, ob dies der beste Ansatz ist, und würde mich interessieren, wie andere mit dem gegenseitigen Ausschluss in Javascript umgehen, aber soweit ich weiß, handelt es sich um einen einfachen Mutex, der praktisch ist.

9
alzclarke

JavaScript ist Single-Threaded ... obwohl Chrome ist vielleicht ein neues Biest (ich denke, es ist auch Single-Threaded, aber jeder Tab hat seinen eigenen JavaScript-Thread ... Ich habe es nicht untersucht im Detail, also zitiere mich nicht dort).

Sie müssen sich jedoch darüber Gedanken machen, wie Ihr JavaScript mehrere Ajax-Anforderungen verarbeitet, die nicht in derselben Reihenfolge zurückkommen, in der Sie sie gesendet haben. Alles, worüber Sie sich wirklich Sorgen machen müssen, ist sicherzustellen, dass Ihre Ajax-Anrufe so gehandhabt werden, dass sie sich nicht gegenseitig auf die Füße treten, wenn die Ergebnisse in einer anderen Reihenfolge zurückkommen, als Sie sie gesendet haben.

Dies gilt auch für Auszeiten ...

Wenn JavaScript Multithreading entwickelt, dann sorgen Sie sich vielleicht um Mutexe und Ähnliches.

5
Mike Stone

Ja, für den Zugriff auf Ressourcen, die von Tabs/Fenstern gemeinsam genutzt werden, können in Javascript Mutexe erforderlich sein, z. B. localStorage .

Wenn ein Benutzer beispielsweise zwei Registerkarten geöffnet hat, ist einfacher Code wie der folgende nicht sicher:

function appendToList(item) {
    var list = localStorage["myKey"];
    if (list) {
        list += "," + item;
    }
    else {
        list = item;
    }
    localStorage["myKey"] = list;
}

Zwischen dem Zeitpunkt, zu dem das localStorage-Element "got" und "set" ist, könnte eine andere Registerkarte den Wert geändert haben. Dies ist im Allgemeinen unwahrscheinlich, aber möglich. Sie müssen die Wahrscheinlichkeit und das Risiko von Konflikten unter bestimmten Umständen selbst beurteilen.

Weitere Informationen finden Sie in den folgenden Artikeln:

3
decates

Ereignisse werden signalisiert, aber die Ausführung von JavaScript erfolgt immer noch mit einem Thread.

Ich verstehe, dass die Engine bei Signalisierung eines Ereignisses stoppt, was sie gerade ausführt, um die Ereignisbehandlungsroutine auszuführen. Nachdem der Handler fertig ist, wird die Skriptausführung fortgesetzt. Wenn die Ereignisbehandlungsroutine einige gemeinsam genutzte Variablen geändert hat, werden diese Änderungen im wiederaufgenommenen Code "aus heiterem Himmel" angezeigt.

Wenn Sie gemeinsam genutzte Daten "schützen" möchten, sollte ein einfaches Boolesches Flag ausreichen.

1
Constantin

JavaScript, das language, kann beliebig viele Threads haben, aber in Browser-Einbettungen der JavaScript-Engine wird jeweils nur ein Callback (onload, onfocus, <script>, etc ...) ausgeführt (per vermutlich). Williams Vorschlag, einen Mutex für Änderungen zwischen der Registrierung und dem Empfang eines Rückrufs zu verwenden, sollte aus diesem Grund nicht zu wörtlich genommen werden, da Sie den dazwischenliegenden Rückruf nicht blockieren möchten, da der Rückruf, der ihn entsperrt, hinter dem aktuellen Rückruf blockiert wird ! (Wow, Englisch ist zum Kotzen, wenn man über Threading spricht.) In diesem Fall möchten Sie wahrscheinlich etwas tun, das dem Redispatching des aktuellen Ereignisses entspricht, wenn ein Flag gesetzt ist, entweder wörtlich oder mit setTimeout ().

Wenn Sie eine andere Einbettung von JS verwenden und mehrere Threads gleichzeitig ausführen, kann dies zu Problemen führen. Aufgrund der Art und Weise, wie JS Rückrufe so einfach verwenden kann und Objekte für den Eigenschaftenzugriff sperrt, ist das explizite Sperren bei weitem nicht erforderlich . Es würde mich jedoch überraschen, wenn eine Einbettung für allgemeinen Code (z. B. Spieleskript), die Multi-Threading verwendet, nicht auch einige explizite Sperrprimitive liefert.

Sorry für die Textwand!

1
Simon Buchan