Les Web workers - Rappel sur les concepts

1. Rappel sur les concepts

Nous allons parler ici de Javascript principalement. Javascript, qui comme tout le monde le sait, n’est pas Java (grosse erreur que beaucoup de personnes font encore...) est un langage de programmation à la fois client et (depuis peu) serveur, avec Node js. La particularité du Javascript c’est qu’il est particulièrement utile en asynchrone et surtout qu’il permet de réaliser des interfaces et des actions sur une page sans avoir à la recharger. De plus couplé à des techniques comme l’Ajax le chargement de contenu peut être différé ou même caché aux yeux des utilisateurs, laissant ainsi l’impression que le site fonctionne seul et n’a pas besoin de rechargement.

Mais le Javascript n’a pas que des bons côtés; un de ces points faibles selon moi est qu’il est mono-thread.

Un thread c’est quoi?

Pour vous expliquer (ou réexpliquer) le concept de thread je vais devoir faire un peu de technique et vous décrire des concepts que vous utilisez tous les jours sans pour autant comprendre comment ils fonctionnent.

Dans la vie de tous les jours on dit que certains humains sont multi-tâches, c'est-à-dire qu’ils peuvent faire deux actions à la fois voir plus. Pour les ordinateurs s'est différé, un ordinateur gère des tâches grâce à un Sheduler qui va lui permettre d’allouer un temps d’exécution à chaque tâche. Prenons un exemple, vous souhaitez copier un dossier de photos d’un endroit à un autre. Vous lancez la copie et souhaitez pendant cette copie allez consulter vos emails. Le Sheduler va donc allouer un temps d’exécution à la copie, puis va l’interrompre pour lancer votre gestionnaire d’emails, puis interrompre ce dernier pour reprendre avec la copie et ainsi de suite. Le Sheduler réalisera ce système d’actions pour chaque tâche dans sa liste. Vous me direz “Oui mais s'il interrompe une tâche pour en gérer une autre, ce n'est pas du simultané!”, et bien techniquement si, la tâche de la copie n’est pas finie et est commencée, elle est donc en cours, comme l’exécution de votre gestionnaire d’emails.

Cependant depuis les années 2000 et l’arrivée des processeurs multi-coeurs il est réellement possible de faire du multi-tâches comme vous l’imaginer. Le Sheduler peut donc déléguer à chaque coeur une action au même moment, on appelle ça une exécution concurrente. Un programme doit indiquer qu’une partie de son code ne s’exécute plus dans la même pile que le code principal, ce n’est pas une action automatique.

Une pile c’est quoi?

Une pile (pile sémantique) est un ensemble d’instructions que l’ordinateur doit exécuter, à ne pas confondre avec la pile d’exécution qui, elle, liste les fonctions actives du programme. Par ailleurs, chaque pile sémantique contient une pile d’exécution.

Revenons en a notre thread, un thread c’est un fil d’exécution qui contient une pile sémantique et qui se charge de l’exécuter. Facile!

Un process (processus) contient-lui un ou plusieurs threads, le sheduler va donc se charger de séquencer ces processus pour qu’ils puissent s’exécuter en même temps.

Les threads à l’intérieur du même processus peuvent avoir un mémoire partagé alors que les process ne partagent rien.

En quoi ça nous intéresse pour du Javascript ?

Comme dit précédemment, le Javascript s’exécute dans un seul thread. C’est le moteur qui définit s'il a besoin d’exécuter le code dans un nouveau thread ou dans un nouveau processus. Le développeur ne peut pas choisir quelle méthode utilisée.

Dans un développement utilisant plusieurs threads il est nécessaire de pouvoir faire communiquer les exécutions pour un bon déroulement. Il est rare que les deux codes soient totalement indépendants.

Comment faire pour communiquer entre vos threads ? Il existe deux méthodes, le shared memory et le message passing.

Le shared memory est le fait d’avoir un espace mémoire partagé entre les threads où des variables communes sont stockées. Dit comme ça on dirait que c’est vraiment cool, mais il y a de gros défauts à ce système. Le premier est l’accès dit concurrent. Je vais vous expliquer par un exemple ce sera plus simple :

exemple : une variable contient un identifiant de base de données “id=1”. Deux threads vont vouloir y accéder pour l’incrémenter. Les deux threads vont donc récupérer la valeur “id=1” et l’incrémenter chacun en “id=2”. à la fin de l’exécution notre id sera de valeur 2 au lieu de 3. Notre deuxième thread écrasant l’incrémentation du premier.

Le second défaut et deadlocks sont le fait de planter totalement un script en demande l’accès à des ressources partagées au même instant. Pour expliquer rapidement, imaginez un script A qui bloc une ressource partagée pour ne pas avoir d’accès concurrent et demande l’accès à une autre ressource partagée qui elle, est bloquée par un script B qui demande l’accès à la ressource que le script A a bloqué ...Résultat aucun des deux scripts ne peut se finir, donc plantage.

Ensuite on a donc la deuxième méthode qui s’appelle le message passing (passage de message). Comme son nom l’indique cette méthode reposer sur un principe d’envoi de messages entre deux threads. Là où le shared memory partage un espace mémoire entre les threads, le passage de message n’en a pas, chaque thread est indépendant et ne connaît pas le statut ou les actions que réalise l’autre. Il sait juste qu’il a reçu une demande et qu’il doit y répondre. Il faut aussi savoir que l’envoi de messages n’est pas bloquant, vous pouvez envoyer le message et continuer votre traitement en attendant le callback (la réponse).

Mais tous ces concepts semblent bien obscurs...passons à l’étape 2! les workers Dedicated.