Site icon Blog ARC Optimizer

Maîtriser la boucle d’événements dans Node.js

Maîtriser la boucle d’événements dans Node.js


Une compréhension approfondie de la boucle d’événements peut être l’une des choses que de nombreux développeurs négligent. Cet article couvre une explication détaillée de ce que c’est et comment cela fonctionne.

Il était une fois, nous n’avions qu’un seul processus. Si nous examinons le MS-DOS et le premier système d’exploitation Apple, ils pourraient exécuter une chose à la fois. Il n’y avait pas de tâche en arrière-plan ni d’exécution de plusieurs programmes. Lors de l’exécution d’un programme, si vous deviez passer à un autre programme, il arrêtait automatiquement celui en cours, ce qui était assez limitant. Afin de résoudre ce problème, le multitâche coopératif a été introduit, ce qui rend les choses beaucoup plus efficaces.

La façon dont fonctionne le multitâche coopératif est que vous avez une application en cours d’exécution, puis elle arrive à un stade où elle fait une pause pour que d’autres choses puissent s’exécuter. Cela se fait principalement via une fonction écrite dans l’application appelée yield, qui signale au système d’exploitation que l’application s’est terminée afin que les autres applications puissent continuer à s’exécuter. Pourtant, le problème ici est que cela dépend de l’application de l’utilisateur qui appelle la fonction yield, c’est-à-dire que si la fonction yield n’est pas appelée, les programmes continuent de s’exécuter.

Le multitâche coopératif était une amélioration – nous pouvions exécuter plusieurs choses, mais nous avions encore quelques problèmes avec, et la stabilité était le principal problème.

Cela a conduit à l’introduction de multitâche préemptif, où l’on ne dépend plus de l’application. Au lieu de cela, le système d’exploitation peut mettre en pause n’importe quelle application à un moment donné. Il mettra l’application en pause, enregistrera l’état ailleurs et chargera une autre application. Il aide le système d’exploitation à fonctionner sans dépendre des applications, gagnant ainsi plus de stabilité et d’efficacité.

Tant de gens ont continué à chercher comment améliorer les performances, en particulier lorsque des processeurs multicœurs ont été lancés au début des années 2000. Des questions telles que « Comment les processeurs multicœurs peuvent-ils être utilisés pour des performances maximales ? » a donné lieu à de nombreuses recherches qui ont abouti à multi-threading symétrique (SMT).

Avec CMS le système d’exploitation peut tirer parti des nouvelles instructions au niveau de l’assemblage dans le processeur lui-même. Par conséquent, nous exécutons les instructions par étapes.

Introduction au thread et aux processus

Le processus peut être défini comme le programme en cours d’exécution, tandis qu’un thread est une unité d’exécution de base. Chaque programme peut contenir plusieurs processus, et chaque processus a plusieurs threads qui s’y exécutent.

Un thread est une unité de base d’exécution ou d’utilisation du processeur ; il comprend un ID de thread, un compteur de programme, un ensemble de registres et une pile. Il partage également avec d’autres threads appartenant au même processus sa section de code, sa section de données et d’autres ressources du système d’exploitation, telles que les fichiers ouverts et les signaux.

Un processus traditionnel/lourd a un seul fil de contrôle. Si un processeur a plusieurs threads de contrôle, il peut effectuer plusieurs tâches à la fois.


Vue d’ensemble des processus et des threads

Cet article couvrira la boucle d’événements dans Node.js, son fonctionnement, sa fonction, la programmation asynchrone et synchronisée et comment utiliser efficacement la boucle d’événements.

Conditions préalables

Pour suivre cet article, vous devez avoir :

  • Connaissance de base de Node.js
  • Node installé sur votre PC
  • Un éditeur de code

Qu’est-ce que la boucle d’événement ?

JavaScript est un langage asynchrone à un seul thread – c’est une pile d’appels et il ne peut faire qu’une seule chose à la fois. Cette pile d’appels est présente dans le moteur JavaScript et tout le code du JavaScript est exécuté dans la pile d’appels.

function b() {
  console.log("b");
}

b();
console.log("end");

Chaque fois qu’un programme JavaScript est exécuté, un contexte d’exécution global est créé ; il est ensuite déplacé vers la pile des appels. En regardant le code ci-dessus, pour que JavaScript exécute le code, il crée d’abord le contexte d’exécution global dans la pile d’appels, puis la fonction « b » se voit allouer de la mémoire et déplacée vers la pile d’appels pour exécution, qui imprime ensuite « b ” à la console.

Une fois la fonction exécutée, elle est sortie de la pile des appels et le code suivant commence son exécution. C’est ainsi que le moteur JavaScript exécute son programme.

console.log("Start");

setTimeout(function cb() {
  console.log("Callback");
}, 5000);

console.log("End");

Dans le cas d’un délai d’attente ou d’un délai d’exécution du code, le contexte d’exécution global est d’abord créé et poussé à l’intérieur de la pile des appels. L’ensemble du bloc de code s’exécutera ligne par ligne, en commençant par imprimer Start sur la console, qui est exécuté dans le contexte d’exécution global. Il passe à la fonction setTimeout, qui enregistre un rappel et démarre également une minuterie de 5000 ms et passe à la ligne suivante sans attendre ; cette ligne imprime End sur la console, puis le contexte d’exécution global sort de la pile des appels puisque nous avons fini d’exécuter le code. Pendant que toutes ces choses se produisent, la minuterie tourne toujours.

Dès que la minuterie a fini de compter, la fonction de rappel doit être exécutée, ce qui signifie qu’elle doit trouver un moyen de déplacer le rappel à l’intérieur de la pile des appels pour exécuter la fonction ; c’est là que le boucle d’événements et file d’attente de rappel entrer en jeu. Étant donné que la fonction de rappel ne peut pas accéder directement à la pile des appels, elle doit passer par la file d’attente de rappel. Une fois la minuterie expirée, la fonction de rappel est déplacée dans la file d’attente de rappel et la boucle d’événements permet de placer les fonctions de rappel de la file d’attente de rappel dans la pile des appels.

La boucle d’événements sert de contrôleur d’accès qui recherche une fonction en attente dans la file d’attente de rappel. Si oui, il est poussé à l’intérieur de la pile d’appels.

Passons en revue un autre exemple de code avant de continuer.

console.log("start");

setTimeout(function cb() {
  console.log("Callback");
}, 5000);

fetch("https://api.netflix.com")
.then(function cbNet() {
  console.log("let have fun with Netflix")
});

console.log("End")

Ainsi, dans le scénario ci-dessus, nous avons une fonction setTimeout, attendant le temps avant d’exécuter la fonction, puis la fonction fetch, attendant que les données soient extraites du point de terminaison donné.

Comme les exemples précédents, il démarre l’exécution du code en exécutant la première ligne de code dans la pile des appels, qui affichera Start sur la console. Il le sort de la pile des appels et passe à la fonction timeout, stockée en tant que rappel jusqu’à l’expiration du délai. Il passe immédiatement à la ligne suivante, stockée en tant que rappel jusqu’à ce que les données soient extraites du point de terminaison. Enfin, il passe à la dernière ligne du code, qui imprime End sur la console ; une fois que le délai d’attente expire ou que les données sont reçues du point de terminaison, le rappel est déplacé vers la file d’attente de rappel, qui est ensuite déplacée séquentiellement par la boucle d’événements vers la pile d’appels pour exécution.

Comprendre la programmation synchrone et asynchrone

La programmation synchrone est un type de programmation où le code est exécuté du haut du fichier vers le bas du fichier sans sauter aucune ligne.

La programmation asynchrone, d’autre part, exécute le code de haut en bas, mais se heurtera à certaines fonctions ou codes asynchrones qui devront être divisés et exécutés séparément car ils doivent attendre ou effectuer certaines opérations avant que la fonction puisse être exécuté, ce qui prend souvent du temps.

let a = 1;
let b = 2;

console.log(a);
console.log(b);

Dans le code ci-dessus, la sortie sera un en premier et deux en second. Il s’agit d’un code synchrone qui s’exécute sans délai.

let a = 1;
let b = 2;
console.log(a);

setTimeout(function cs(){
  console.log("asyncronous");
}, 100)

console.log(b);

Dans le code ci-dessus, la fonction de temporisation a besoin d’un délai de 100 ms, ce qui fait que l’exécution du code attend jusqu’à l’expiration du délai. La sortie sera 1, 2, « asynchrone » car le délai d’attente sera retardé, donnant à l’autre fonction le temps de s’exécuter.

La boucle d’événements dans Node.js

Node.js est à thread unique et la boucle d’événements s’exécute sur un seul thread appelé le thread principal, mais il y a une petite différence avec Node.js. Il y a certaines choses en C++ trouvées dans Node.js, ayant un ratio de 2/3 JavaScript : 1/3 C++.

Regardons des exemples :


const crypto = require('crypto');

const Num = 3;

for (let i = 0; i < Num; i++) {
  crypto.pbkdf2Sync("secrect_key", "water", 1000, 512, 'sha512');
}

const crypto = require('crypto');

const Num = 3;

for (let i = 0; i < Num; i++) {
  crypto.pbkdf2("secrect_key", "water", 1000, 512, 'sha512', ()=>{});
}

En examinant le module de chiffrement, examinons la fonction pbkd (Password-Based Key Derivation). Cela peut fonctionner à la fois en synchronisation et en asynchrone ; l’exécution de ce code de manière synchrone avec le nombre de requêtes défini sur 3 exécutera le code trois fois en attendant que l’une se termine avant d’exécuter l’autre.

Cela prend plus de temps pour terminer l’exécution, tandis que l’exécution du code en asynchrone exécutera les trois en parallèle, réduisant ainsi le temps d’exécution.

Le nœud ne crée pas de nouveau thread pour chaque requête. Au lieu de cela, il utilise un nombre pré-alloué de threads appelé le pool de threads; la valeur par défaut est quatre qui seront réutilisées pour tout le travail, donc une fois la demande lancée, elle les affectera aux threads du pool de threads. Par conséquent, une fois que tous les threads du pool de threads sont occupés, il place la demande dans une file d’attente jusqu’à ce que l’un des threads de travail soit libre pour l’affectation.

Phases de boucle d’événement

Voici la liste des phases de la boucle d’événements.

Phase de piscine

Tout le code JavaScript synchrone sera exécuté dans la phase de pool de la boucle d’événements.

console.log("1")
console.log("2")

Le code ci-dessus est synchrone et sera exécuté dans la phase de pool car il n’y a pas de retard dans le code.

Minuteur

Ces fonctions exécutent leurs tâches en tant que rappels basés sur un délai d’attente spécifique, c’est-à-dire que le délai d’attente doit expirer avant que la fonction ne soit exécutée.

console.log("start");

setTimeout(function cb() {
  console.log("Callback");
}, 5000);

console.log("End");

Rappels d’entrée/sortie

Le processus par lequel une application n’a pas besoin d’attendre une demande pour obtenir des données spécifiques avant de s’exécuter ; le code est exécuté de manière asynchrone.

fs.readFile("/nsa.md", (error, data) => {
  if (error) throw error;
});

mainFunc();

Utiliser le fs.readFile comme un classique Input/Output operation, une demande de lecture du système de fichiers est transmise au système d’exploitation par Node, puis le code continuera à exécuter la ligne de code suivante : mainFunc(). Une fois la demande terminée, une fonction de rappel sera placée dans la file d’attente de rappel.

Inactif

Lorsque la boucle d’événements fonctionne sur les fonctions internes de tous les rappels.

DéfinirImmédiat

Une minuterie spéciale, introduite par Node.js, qui exécute un rappel immédiatement après qu’une phase de boucle d’événement devient inactive. Une fois que setImmediate est appelé, il est exécuté avant les autres fonctions de minuterie.

Fermer l’événement

Cet état de boucle d’événements exécutera de manière cohérente tous les événements de fermeture d’une fonction, par exemple, process.exit().

Conclusion

Cet article traite des processus, des threads, des fonctions asynchrones et synchrones, de la boucle d’événements et de son fonctionnement dans Node.js.




Source link
Quitter la version mobile