web-dev-qa-db-fra.com

Des mutex sont-ils nécessaires en javascript?

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 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 m'interroge sur les effets de l'utilisation de fonctions appelées par setTimeout() et XmlHttpRequestonreadystatechange sur des variables accessibles à l'échelle mondiale.

99
Ovesh

Javascript est défini comme rentrant langue qui signifie qu'il n'y a pas de thread exposé à l'utilisateur, il peut y avoir des threads dans l'implémentation. Les fonctions telles que setTimeout() et 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 le prochain événement 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'il envoie un XmlHttpRequest qui appelle un rappel, la structure des données change de manière destructrice, et vous avez un autre bouton qui modifie directement la même structure de données, entre le moment où l'événement a été tiré 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 pourrait alors perdre la valeur.

Bien que vous puissiez créer une condition de concurrence comme celle-ci, il est très facile d'empêcher cela dans votre code car chaque fonction sera atomique. Ce serait beaucoup de travail et il faudrait des schémas de codage étranges pour créer la condition de concurrence.

95
William

Les réponses à cette question sont un peu dépassées mais 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-travailleurs:
multithreading en javascript à l'aide de webworkers
Mozilla sur les webworkers

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

18
gorillatron

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 demande 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 à l'arrière-plan. Vous devrez peut-être un peu de code pour vous protéger contre le déclenchement d'utilisateurs heureux en cliquant et en créant 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.

9
alzclarke

JavaScript est un thread unique ... bien que Chrome peut être une nouvelle bête (je pense qu'il est également 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à-bas).

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

Cela vaut aussi pour les temps morts ...

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

5
Mike Stone

Oui, des mutex peuvent être requis en Javascript lors de l'accès à des ressources partagées entre des 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 aurait pu modifier la valeur. C'est généralement peu probable, mais possible - vous devez juger par vous-même de la probabilité et du risque associés à tout conflit dans votre situation particulière.

Consultez les articles suivants pour plus de détails:

3
decates

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

Ma compréhension est 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 reprendra ces modifications "à l'improviste".

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

1
Constantin

JavaScript, le langue, 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 intermédiaire car le rappel qui le déverrouillera sera bloqué derrière le rappel actuel ! (Wow, l'anglais craint de parler de threading.) Dans ce cas, vous voudrez probablement faire quelque chose dans le sens de redistribuer l'événement en cours si un indicateur est défini, littéralement ou avec setTimeout ().

Si vous utilisez une intégration différente de JS, et qui exécute 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 le code général (par exemple, les scripts de jeu) qui utilisait le multi-threading ne donnait pas également des primitives de verrouillage explicites.

Désolé pour le mur de texte!

1
Simon Buchan