Les Mutex sont-ils nécessaires en javascript?

104

J'ai vu ce lien: Implémentation de l'exclusion mutuelle en JavaScript . D'un autre côté, j'ai lu qu'il n'y a pas de threads en javascript, mais qu'est-ce que cela signifie exactement?

Lorsque des événements se produisent, où dans le code peuvent-ils s'interrompre?

Et s'il n'y a pas de threads dans JS, dois-je utiliser des mutex dans JS ou non?

Plus précisément, je me demande sur les effets de l' utilisation des fonctions appelées par setTimeout()et XmlHttpRequest« s onreadystatechangesur des variables globalement accessibles.

Ovesh
la source
1
Non, pas de mutex ou tout autre outil de contrôle de concurrence en javascript. Voir Pourquoi aucun outil de contrôle d'accès concurrentiel en javascript .
Uzair Farooq

Réponses:

101

Javascript est défini comme un langage réentrant , ce qui signifie qu'aucun thread n'est exposé à l'utilisateur, il peut y avoir des threads dans l'implémentation. Les fonctions telles setTimeout()que les rappels asynchrones doivent attendre que le moteur de script se mette en veille avant de pouvoir s'exécuter.

Cela signifie que tout ce qui se passe dans un événement doit être terminé avant que l'événement suivant ne soit traité.

Cela étant dit, vous pouvez avoir besoin d'un mutex si votre code fait quelque chose où il s'attend à ce qu'une valeur ne change pas entre le moment où l'événement asynchrone a été déclenché et le moment où le rappel a été appelé.

Par exemple, si vous avez une structure de données où vous cliquez sur un bouton et qu'elle envoie une XmlHttpRequest qui appelle un rappel, la structure de données change de manière destructive, et vous avez un autre bouton qui change directement la même structure de données, entre le moment où l'événement a été déclenché et lorsque le rappel a été exécuté, l'utilisateur aurait pu cliquer et mettre à jour la structure de données avant le rappel, ce qui pouvait alors perdre la valeur.

Bien que vous puissiez créer une condition de concurrence comme celle-là, il est très facile de l'empêcher dans votre code car chaque fonction sera atomique. Ce serait beaucoup de travail et nécessiterait des modèles de codage étranges pour créer la condition de concurrence en fait.

William
la source
14
Ce n'est pas du tout difficile de créer cette condition de concurrence: par exemple, j'ai un événement "onkeyup" dans un champ, qui déclenche un appel ajax à une base de données pour obtenir des valeurs. La saisie rapide des données peut facilement conduire à des résultats dans le désordre.
thomasb
19

Les réponses à cette question sont un peu dépassées bien que correctes au moment où elles ont été données. Et toujours correct si vous regardez une application javascript côté client qui n'utilise PAS de webworkers.

Articles sur les web-workers:
multithreading en javascript avec les webworkers
Mozilla sur les webworkers

Cela montre clairement que javascript via des web-workers a des capacités de multithreading. En ce qui concerne la question, les mutex sont-ils nécessaires en javascript? Je n'en suis pas sûr. Mais ce post de stackoverflow semble pertinent:
Exclusion mutuelle pour N threads asynchrones

gorillatron
la source
3
explosion du passé, mais j'ai rencontré le besoin de mutex lorsque plusieurs onglets accèdent au même stockage local
psp
3
Les WebWorkers n'affectent pas la rentrée car ils ne partagent aucun état variable et ne communiquent avec le thread principal qu'en passant des messages, qui déclenchent des événements.
Alnitak
9

Comme le souligne @william,

vous pouvez avoir besoin d'un mutex si votre code fait quelque chose où il s'attend à ce qu'une valeur ne change pas entre le moment où l'événement asynchrone a été déclenché et le moment où le rappel a été appelé.

Cela peut être généralisé davantage - si votre code fait quelque chose où il attend le contrôle exclusif d'une ressource jusqu'à ce qu'une requête asynchrone soit résolue, vous aurez peut-être besoin d'un mutex.

Un exemple simple est celui où vous avez un bouton qui déclenche un appel ajax pour créer un enregistrement dans le back-end. Vous aurez peut-être besoin d'un peu de code pour vous empêcher de déclencher des utilisateurs satisfaits en cliquant et de créer ainsi plusieurs enregistrements. il existe un certain nombre d'approches à ce problème (par exemple, désactiver le bouton, activer en cas de succès ajax). Vous pouvez également utiliser un simple verrou:

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

Je ne sais pas si c'est la meilleure approche et je serais intéressé de voir comment les autres gèrent l'exclusion mutuelle en javascript, mais pour autant que je sache, c'est un simple mutex et c'est pratique.

alzclarke
la source
4
J'appellerais difficilement cela un mutex, du moins pas dans le sens traditionnel, car vous n'avez pas deux threads en cours d'exécution dans le contexte d'un seul bloc à tout moment.
Ovesh
10
un mutex est simplement un algorithme qui aide à «éviter l'utilisation simultanée d'une ressource commune». Bien que le multithreading crée un besoin de mutex, rien dans la définition n'indique qu'un mutex est spécifique à la situation que vous décrivez.
alzclarke
1
Vous avez raison sur la définition formelle du mutex. Mais ce n'est guère ce à quoi les gens pensent lorsqu'ils parlent de mutex dans le monde réel.
Ovesh
Cela ne fonctionne pas comme prévu. Malheureusement, des clics répétés déclencheront toujours l'appel ajax. Une autre idée?
Mohammed Shareef C
1
À peu près sûr, cela devrait être encapsulé dans un whileavec setTimeoutou un setIntervalavec clearIntervalaprès n échecs afin que vous ayez une logique de nouvelle tentative et de délai d'attente. Laisser tel quel signifie que vous contournerez simplement le code verrouillé. La gestion externe des mutex et des objets partagés est aussi importante que les implémentations elles-mêmes.
MrMesees
6

JavaScript est un thread ... bien que Chrome soit peut-être une nouvelle bête (je pense que c'est aussi un thread unique, mais chaque onglet a son propre thread JavaScript ... Je ne l'ai pas examiné en détail, alors ne me citez pas Là).

Cependant, une chose dont vous devez vous soucier est de savoir comment votre JavaScript gérera plusieurs demandes ajax qui ne reviennent pas dans le même ordre que vous les envoyez. Donc, tout ce dont vous devez vraiment vous soucier est de vous assurer que vos appels ajax sont traités de manière à ne pas marcher sur les pieds l'un de l'autre si les résultats reviennent dans un ordre différent de celui que vous leur avez envoyé.

Cela vaut aussi pour les délais d'attente ...

Lorsque JavaScript développe le multithreading, vous vous inquiétez peut-être des mutex et autres ....

Mike Stone
la source
4

Oui, des mutex peuvent être requis en Javascript lors de l'accès aux ressources partagées entre les onglets / fenêtres, comme localStorage .

Par exemple, si un utilisateur a deux onglets ouverts, un code simple comme celui-ci n'est pas sûr:

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

Entre le moment où l'élément localStorage est «obtenu» et «défini», un autre onglet peut avoir modifié la valeur. C'est généralement peu probable, mais possible - vous devrez juger par vous-même de la probabilité et du risque associés à toute contestation dans votre situation particulière.

Consultez les articles suivants pour plus de détails:

décates
la source
2

JavaScript, le langage , peut être aussi multithread que vous le souhaitez, mais les intégrations de navigateur du moteur javascript n'exécutent qu'un seul rappel (onload, onfocus, <script>, etc ...) à la fois (par onglet, probablement). La suggestion de William d'utiliser un Mutex pour les changements entre l'enregistrement et la réception d'un rappel ne doit pas être prise trop littéralement à cause de cela, car vous ne voudriez pas bloquer le rappel intervenant car le rappel qui le déverrouillera sera bloqué derrière le rappel actuel ! (Wow, l'anglais est nul pour parler de threading.) Dans ce cas, vous voudrez probablement faire quelque chose comme la redistribution de l'événement actuel si un drapeau est défini, soit littéralement, soit avec setTimeout ().

Si vous utilisez une intégration différente de JS et que vous exécutez plusieurs threads à la fois, cela peut devenir un peu plus risqué, mais en raison de la façon dont JS peut utiliser les rappels si facilement et verrouille les objets sur l'accès aux propriétés, le verrouillage explicite n'est pas aussi nécessaire . Cependant, je serais surpris si une intégration conçue pour du code général (par exemple, des scripts de jeu) qui utilisait le multi-threading ne donnait pas également des primitives de verrouillage explicites.

Désolé pour le mur de texte!

Simon Buchan
la source
0

Les événements sont signalés, mais l'exécution de JavaScript est toujours monothread.

Je crois comprendre que lorsqu'un événement est signalé, le moteur arrête ce qu'il exécute en ce moment pour exécuter le gestionnaire d'événements. Une fois le gestionnaire terminé, l'exécution du script reprend. Si le gestionnaire d'événements a modifié certaines variables partagées, le code repris verra ces modifications apparaître «à l'improviste».

Si vous voulez "protéger" les données partagées, un simple drapeau booléen devrait suffire.

Constantin
la source