Optimisez vos Applications avec le Multithreading

Optimisez vos Applications avec le Multithreading

Un Ordre Bien Défini

Le rôle d'un développeur est de définir les différentes instructions que votre ordinateur devra exécuter pour mener à bien un programme. Lors de son exécution, votre ordinateur lira chacune de ces instruction, et les exécutera les unes après les autres. Ce point est très important, car si une seule de ces instruction était erronée, tout votre programme serait impacté !

Je vous propose de voir cela au travers d'un exemple simple en apparence : La réalisation d'un mode multijoueur dans un jeu-vidéo. Notre objectif est de faire apparaître différents joueurs sur une même carte, chacun d'entre eux étant synchronisé avec les autres via une base de donnée sur un serveur. À chaque actualisation de l'écran, votre ordinateur donc devra effectuer les tâches suivantes :

• Afficher le décors du jeu.

• Déplacer le joueur principal.

• Afficher le joueur principal.

• Récupérer les positions des autres joueurs.

• Afficher ces autres joueurs.

• Et enfin, actualiser l'écran.

Je vous propose de schématiser ce fonctionnement, pour y voir plus clair.

Synchronous

En théorie, chacune de ces instructions se déclenche une fois que la précédente est terminée, et ainsi de suite pendant toute la durée de votre partie.

Un problème se pose toutefois avec un tel fonctionnement : Chacune de ces instructions prend un certain temps pour s'exécuter, et ce délai dépend de l'action que vous allez effectuer. Par exemple, une connexion au réseau pour y récupérer la position d'un joueur est beaucoup plus long que l'affichage de ce joueur à proprement parler.

Malheureusement, ni vous ni moi ne pouvez influencer ce délai d'exécution, car il est intrinsèquement lié à votre ordinateur.

Pendant ce temps, votre ordinateur ne peux rien faire, car il attends la fin de l'instruction en cours. Dans le cas d'un accès mémoire, le délai étant tellement court que ni vous ni votre ordinateur ne pourriez faire quoi que ce soit. Mais dans le cas d'une opération plus longue, comme une connexion à un serveur, il est possible que votre ordinateur se bloque pendant plusieurs centaines de millisecondes, ce qui est inconcevable si vous ne voulez pas faire fuir vos utilisateurs ! C'est ce qui s'appelle une exécution synchrone.

Paralléliser les instructions

Dans un jeux-vidéo, ou n'importe quel site web, la réactivité de votre application est un facteur déterminant si vous ne voulez pas frustrer vos utilisateurs. Vous ne pouvez donc pas accepter que votre ordinateur attende inutilement la fin d'une instruction sans rien faire d'autre. Comme le problème vient du fonctionnement à la chaine des instructions, nous allons essayer de les désynchroniser, pour qu'elles s'exécutent en parallèle, et non plus les unes à la suite des autres. En terme technique, cela s'appelle le multithreading.

Pour faire simple, un thread est une suite d'instructions que votre ordinateur va exécuter. Lorsque vous développez une application, celle-ci est automatiquement mise en place dans un thread unique, et fonctionne comme nous l'avons vu au dessus. Mais l'intérêt du multithreading est, comme son nom l'indique, de créer plusieurs threads, correspondant à plusieurs suites d'instructions. Nous allons donc créer un nouveau thread, et y mettre les opérations qui ralentissent notre thread principal.

Cela va nous permettre d'avoir un thread principal qui s'exécute rapidement, et un second thread plus lent, mais ne ralentissant pas le thread principal !

Asynchronous

Vous remarquerez que tous les threads ont un objectif commun : Mettre à jour l'écran. Pour y parvenir, il est nécessaire de leur donner un où plusieurs paramètres en lien avec cet objectif commun. Ici, nous pouvons utiliser un pointeur faisant référence à l'écran.

Ce paramètre est au coeur du multithreading. Il permet à chaque thread de fonctionner de son coté, et à la vitesse qu'il veut, et de mettre à jour l'écran dès qu'il a terminé son cycle.

Attention cependant : Chaque thread doit être indépendant du reste du programme. Par exemple, nous ne pouvons pas paralléliser la récupération de la position du joueur avec son affichage, car cette dernière implique de connaître sa position, et donc que l'instruction précédente soit terminée.

Pour vous aider à comprendre ce concept, je vous propose une petite comparaison avec la vie réelle. Imaginez un pizzaïolo qui fait cuire des pizzas une par une dans son four. Sa capacité de travail est délimitée par le temps de cuisson d'une pizza, et si le four venait à tomber en panne, toute sa production serait interrompue. Mais s'il décide d'investir dans un second four, il pourra faire deux services en même temps, et pourra continuer à travailler même en cas de panne de l'un des deux fours.

Si vous avez compris cet exemple, remplacez les pizzas par les instructions de votre programme, et les fours par les différents threads, et vous obtiendrez un parfait exemple du fonctionnement du multithreading !

Le Multithreading est Partout

Je vous ai donné un exemple de multithreading dans les jeux-vidéo, mais il faut savoir que son utilisation est omniprésente dans toute application moderne. Un exemple que vous avez probablement déjà utilisé sans même vous en rendre compte est l'utilisation de fonctions de callback en JavaScript.

Pour rappel, une fonction de callback est une fonction prédéterminée, qui est appelée en réponse à un événement donné. Pas plus loin que sur ce site, de nombreuses fonctions de callback sont définies. Regardez le bouton d'inscription à ma Newsletter, et plus exactement son code JavaScript :

 

$("#newsletterForm").submit(function(event) {
    event.preventDefault();

    alert("Merci de votre inscription !");
});

 

Il s'agit d'une fonction de callback, qui sera appelée lorsque le formulaire sera envoyé. Votre navigateur va exécuter cette fonction uniquement lorsque le formulaire sera envoyé, et donc que l'utilisateur aura saisi son adresse email. Ensuite, il suffira d'enregistrer cette adresse email, (Par exemple avec une requête AJAX) et remercier le visiteur pour son inscription.

Quel est le rapport entre les fonctions de callback et les threads ? Et bien celles-ci utilisent des threads pour programmer leur déclenchement. Sans thread, JavaScript devrait vérifier manuellement à chaque milliseconde l'état de chaque évènement, et éventuellement appeler les fonctions adéquates qui bloqueraient la navigation de l'utilisateur. Alors que là, votre navigateur va simplement créer un thread pour chaque fonction de callback, en spécifiant l'évènement demandé. Une fois celui-ci activé, la fonction sera exécutée directement depuis le thread, ce qui n'entravera pas le reste du programme.

Enfin, je vous ai parlé de threads logiciel, gérés par votre système d'exploitation. Mais depuis quelques années, nous assistons à l'apparition de processeur multicoeurs, qui permettent d'effectuer du multithreading de façon matérielle. Ce serait un peu compliqué à expliquer ici, mais cela permet à chaque coeur de votre processeur de superviser un thread différent, pour un fonctionnement globale encore plus rapide.

Le multithreading est un concept capital en programmation, et permet de créer différents fils d'exécution. Le résultat est un ensemble de sous-programmes qui fonctionnent en parallèle, afin d'optimiser le délai d'exécution de chaque opération. Ce principe a gagné en popularité au cours des dernières années, et est aujourd'hui extrêmement utilisé en informatique, de la programmation de jeux-vidéo en réseau, jusqu'au fonctionnement des sites internet modernes.

Écrit par Pythony le 26/01/2020.

Qu'avez-vous pensé de cet article ?

Autres Articles

Hello World de Pythony

Hello World de Pythony

Lorsque l'on débute un nouveau langage de programmation, la tradition est de commencer par un programme affichant le message "Hello World !" à l'écran. Et c'est également par ce message que je tenais à commencer mon premier article sur ce blog. Au cours de ma vie, j'ai eu l'occasion de travailler sur de nombreux projets, et ce site est l'un d'entre eux. Depuis de longues années, je rêve de pouvoir vivre de ma passion, et je suis sur le point d'y parvenir

Lire "Hello World de Pythony"
Découvrez l'Architecture Model-View-Controller

Découvrez l'Architecture Model-View-Controller

Lorsque vous démarrez un nouveau projet, l'une des premières étapes est de déterminer l'architecture de votre application. Celle-ci définie la façon dont les différents fichiers de votre projet vont communiquer entre eux, depuis la requête de l'utilisateur, jusqu'à la génération d'une page HTML. Il existe en effet plusieurs méthodes pour concevoir un même site, et il est donc important d'y réflechir correctement avant de commencer un projet

Lire "Découvrez l'Architecture Model-View-Controller"
Maîtriser le Terminal

Maîtriser le Terminal

Bien que méconnu du grand public, le terminal est un élément essentiel au bon fonctionnement de tout système d'exploitation. Derrière ces lignes, incompréhensibles pour la majorité des personnes, se cache le fonctionnement précis de chaque action que votre ordinateur sera amené à exécuter. De la simple création de fichier, à la compilation d'un code source, le terminal cache de nombreuses ressources insoupçonnées

Lire "Maîtriser le Terminal"