Codeur JUNIOR confiné - Episode 7, mon premier cluster de calcul distribué : le multi-dé (partie 2)
La suite de notre projet "cluster de calcul", qui s'était soldé par un échec...
On était arrivé à la conclusion suivante : si tout le monde parle en même temps, on ne s'entend plus (ce qui peut être une belle leçon de vie aussi, pour les enfants 😁)
On est donc reparti de zéro. Comment faire pour s'entendre si tout le monde parle en même temps? Réponse : chacun son tour !
Il y a une autre réponse, pas forcément évidente, et on y reviendra plus tard.
Chacun son tour
Les problèmes à résoudre
Déjà, chacun son tour c'est bien joli, mais qui décide l'ordre ? Et ensuite, comment faire pour que tout s'enchaine proprement ?
L'ordre de passage
Le plus simple, pour déterminer l'ordre de passage, est de prendre les microbits "dés" dans l'ordre où ils sont "arrivés" ( = "dans l'ordre où ils ont été allumés").
Seulement, comment savoir qui est arrivé en premier ? Il faut un "chef d'orchestre" qui va dire "hop, toi tu es le premier", "hop, voilà le deuxième", etc... ce chef d'orchestre, ça sera notre master !
- Un dé qui démarre va donc envoyer un message du genre "coucou je suis là"
- Le master lui répondra : "bonjour, toi, tu seras le numéro 1 (ou 2, ou 3, ...)
- Le dé retiendra cette information, il saura qu'il est le numéro 1 (ou 2, ou 3, ...)
⚠️⚠️⚠️⚠️⚠️ Attention : tous les dés allumés vont recevoir tous les messages, et en particuler ce dernier !!! Il faut donc l'écouter uniquement quand on ne connait pas encore son numéro ! Le dé numéro 1 qui va recevoir, comme tout le monde, un message "tu seras le numéro 5" ne doit pas se dire qu'il est désormais le numéro 5 !!!
L’enchaînement
L’enchaînement... on peut le gérer de manière très compliquée (attendre que tous les dés avant moi répondent, avant de répondre moi-même, par exemple...) mais on peut aussi faire très simple : j'attends un bref instant pour chaque dé avant moi (un dixième de seconde par dé suffira)
Le code
Les noeuds de calcul
- Au démarrage, chaque dé indique qu'il est là par le message "Je suis un dé"
- Lorsqu'il reçoit le message "Tu es le numéro ..." et uniquement s'il n'a pas encore son numéro, alors il va extraire le numéro du message, et se l'attribuer
- Lorsqu'il reçoit l'ordre de lancer, il fait son travail il tire un nombre au hasard, il l'affiche et il l'envoie
Le master
- Le master se met en attente
- Chaque fois qu'il reçoit la notification qu'un dé est démarré, il lui envoie son numéro
💡Ca nous permet même de rajouter des dés entre deux tirages !!!
Le reste ne change pas trop :
- secouer le master lance un tirage, et on en avertit les autres dés
- lorsque tout le monde a répondu, on calcule puis affiche le résultat
La démo
On commence avec deux dés : ils se synchronisent bien, le 1er et le 2nd
On lance un tirage (le master est le vert) : 4+5 = 9, tout va bien
On ajoute un 3ème dé : il affiche bien 3 (les autres continuent d'afficher leurs résultats précédents, on s'en moque).
Et enfin nouveau tirage : 4 + 4 + 1 = 9
Et voilà, tout va bien et tout fonctionne 😁
L'autre option
Le souci avec cette approche, c'est que le calcul a beau être distribué, il n'est pas tout à fait exécuté en parallèle (ce qui est un peu l'avantage de base du calcul distribué...).
Pour garder cet aspect, j'avais imaginé une solution avec des groupes radio différents. Chaque dé émet en boucle jusqu'à ce qu'on lui accuse réception, et le master fait un balayage de fréquence pour parcourir les différents groupes radio pour discuter avec chaque dé, séparément.
En pratique, c'est un peu trop compliqué à expliquer - ou en tout cas je n'ai pas trouvé les bons mots 😖
Du coup, on s'est contenté de la solution numéro 1, qui permet en tout cas l'illusion du parallélisme. Et pour des calculs plus longs mais de durée fixe, on aurait en réalité un véritable parallélisme : seuls les résultats partent en séquentiel; donc tout va plutôt bien.
Pour aller plus loin
Nous, on s'est arrêté là. Mais si le coeur vous en dit, il y a possibilité de faire encore mieux :
- suppression d'un dé, via un "health check ping" : vérifier de temps en temps que chaque noeud est toujours là. Le master envoie un ping, les autres répondent par un pong (dans l'ordre !), et s'il en manque un - peu importe lequel - on diminue le nombre de dé. Pour éviter les collisions de numéros, il faudra avoir deux variables : l'indice du dé le plus grand - pour enregistrer les nouveaux; et le nombre de dés effectif - pour les attentes dans les tirages (on aura par exemple 4 dés, numérotés 1, 3, 4, 6)
- timeout : ajouter la possibilité pour le master d'ignorer un dé manquant après un certain temps - et tant qu'à faire, faire une passe de health check ping par dessus ne sera pas un luxe ! Une fois le temps écoulé, on affiche le résultat partiel (quitte à indiquer d'une manière ou d'une autre le souci rencontré)
- pool de dés : chaque tirage pourrait être déclenché par le bouton A un certain nombre N de fois + secousse à la fin, pour indiquer qu'on souhaite N dés. N peut être inférieur à notre nombre de dés, ou même supérieur : on fait plusieurs rounds. Pour ce faire, il faudrait en fait demander nommément à chaque dé un résultat, et parfois même plusieurs fois : il faudrait donc implémenter un gestionnaire de ressources pour le pool de dés.
Voilà. L'objectif n'était pas forcément de démarrer un projet complet open-source, donc on n'est pas allé plus loin, mais on peut toujours en faire plus, pour tous les niveaux !