J'ai personnellement lu le code source de node.js & v8.
Je suis entré dans un problème similaire comme vous lorsque j'ai essayé de comprendre l'architecture node.js afin d'écrire des modules natifs.
Ce que je publie ici, c'est ma compréhension de node.js et cela pourrait également être un peu décevant.
Libev est la boucle d'événements qui s'exécute en fait en interne dans node.js pour effectuer des opérations simples de boucle d'événements. Il est écrit à l'origine pour les systèmes * nix. Libev fournit une boucle d'événements simple mais optimisée sur laquelle le processus peut s'exécuter. Vous pouvez en savoir plus sur libev ici .
LibEio est une bibliothèque pour effectuer une sortie d'entrée de manière asynchrone. Il gère les descripteurs de fichiers, les gestionnaires de données, les sockets, etc. Vous pouvez en savoir plus ici ici .
LibUv est une couche d'abstraction au-dessus de libeio, libev, c-ares (pour DNS) et iocp (pour windows asynchronous-io). LibUv exécute, maintient et gère tous les io et événements dans le pool d'événements. (dans le cas de libeio threadpool). Vous devriez consulter le tutoriel de Ryan Dahl sur libUv. Cela commencera à vous donner plus de sens sur le fonctionnement de libUv et vous comprendrez ensuite comment node.js fonctionne au-dessus de libuv et v8.
Pour comprendre uniquement la boucle d'événements javascript, vous devriez envisager de regarder ces vidéos
Pour voir comment libeio est utilisé avec node.js afin de créer des modules asynchrones, vous devriez voir cet exemple .
Fondamentalement, ce qui se passe à l'intérieur du node.js est que la boucle v8 s'exécute et gère toutes les parties javascript ainsi que les modules C ++ [lorsqu'ils s'exécutent dans un thread principal (selon la documentation officielle, node.js est lui-même à thread unique)]. En dehors du thread principal, libev et libeio le gèrent dans le pool de threads et libev fournissent l'interaction avec la boucle principale. Donc, d'après ce que je comprends, node.js a 1 boucle d'événements permanente: c'est la boucle d'événements v8. Pour gérer les tâches asynchrones C ++, il utilise un threadpool [via libeio & libev].
Par exemple:
eio_custom(Task,FLAG,AfterTask,Eio_REQUEST);
Ce qui apparaît dans tous les modules appelle généralement la fonction Task
dans le threadpool. Une fois terminé, il appelle la AfterTask
fonction dans le thread principal. Considérant que Eio_REQUEST
c'est le gestionnaire de requêtes qui peut être une structure / un objet dont le motif est de fournir une communication entre le threadpool et le thread principal.
process.nextTick
- Lors de la prochaine boucle autour de la boucle d'événements, appelez ce rappel. Ce n'est pas un simple alias de setTimeout (fn, 0), c'est beaucoup plus efficace. À quelle boucle d'événements cela fait-il référence? Boucle d'événement V8?On dirait que certaines des entités discutées (par exemple: libev etc.) ont perdu de leur pertinence, du fait que cela fait longtemps, mais je pense que la question a encore un grand potentiel.
Permettez-moi d'essayer d'expliquer le fonctionnement du modèle événementiel à l'aide d'un exemple abstrait, dans un environnement UNIX abstrait, dans le contexte de Node, à partir d'aujourd'hui.
Point de vue du programme:
La machinerie d'événement ci-dessus est appelée structure de boucle d'événement libuv AKA. Node exploite cette bibliothèque pour implémenter son modèle de programmation événementielle.
Point de vue du nœud:
Alors que la plupart des fonctionnalités sont prises en charge de cette manière, certaines (versions asynchrones) des opérations sur les fichiers sont effectuées à l'aide de threads supplémentaires, bien intégrés dans la libuv. Alors que les opérations d'E / S réseau peuvent attendre dans l'attente d'un événement externe tel que l'autre point d'extrémité répondant avec des données, etc., les opérations sur les fichiers nécessitent un certain travail du nœud lui-même. Par exemple, si vous ouvrez un fichier et attendez que le fd soit prêt avec les données, cela ne se produira pas, car personne ne lit réellement! En même temps, si vous lisez à partir du fichier en ligne dans le thread principal, cela peut potentiellement bloquer d'autres activités dans le programme et créer des problèmes visibles, car les opérations sur les fichiers sont très lentes par rapport aux activités liées au processeur. Ainsi, des threads de travail internes (configurables via la variable d'environnement UV_THREADPOOL_SIZE) sont utilisés pour opérer sur les fichiers,
J'espère que cela t'aides.
la source
Une introduction à libuv
Aussi une image qui décrit la boucle d'événement dans Node.js par @ BusyRich
Mise à jour 05/09/2017
Selon cette boucle d'événements doc Node.js ,
Le diagramme suivant présente une vue d'ensemble simplifiée de l'ordre des opérations de la boucle d'événements.
note: chaque case sera appelée "phase" de la boucle d'événements.
Aperçu des phases
setTimeout()
etsetInterval()
.setImmediate()
.setImmediate()
callbacks sont appelés ici.socket.on('close', ...)
.Entre chaque exécution de la boucle d'événements, Node.js vérifie s'il attend des E / S asynchrones ou des minuteries et s'arrête proprement s'il n'y en a pas.
la source
In the node-v0.9.0 version of libuv libev was removed
", mais il n'y a pas de description à ce sujet dans nodejschangelog
. github.com/nodejs/node/blob/master/CHANGELOG.md . Et si libev est supprimé, comment les E / S asynchrones sont-elles effectuées dans nodejs?Il existe une boucle d'événements dans l'architecture NodeJs.
Modèle de boucle d'événement Node.js
Les applications de nœud s'exécutent dans un modèle événementiel à thread unique. Cependant, Node implémente un pool de threads en arrière-plan afin que le travail puisse être effectué.
Node.js ajoute du travail à une file d'attente d'événements, puis un seul thread exécutant une boucle d'événements le récupère. La boucle d'événements saisit l'élément supérieur de la file d'attente d'événements, l'exécute, puis récupère l'élément suivant.
Lors de l'exécution d'un code dont la durée de vie est plus longue ou dont les E / S bloquent, au lieu d'appeler directement la fonction, il ajoute la fonction à la file d'attente d'événements avec un rappel qui sera exécuté une fois la fonction terminée. Lorsque tous les événements de la file d'attente d'événements Node.js ont été exécutés, l'application Node.js se termine.
La boucle d'événements commence à rencontrer des problèmes lorsque nos fonctions d'application se bloquent sur les E / S.
Node.js utilise des rappels d'événements pour éviter d'avoir à attendre le blocage des E / S. Par conséquent, toutes les demandes qui effectuent des E / S de blocage sont exécutées sur un thread différent en arrière-plan.
Lorsqu'un événement qui bloque les E / S est extrait de la file d'attente d'événements, Node.js récupère un thread du pool de threads et y exécute la fonction au lieu de sur le thread de la boucle d'événements principal. Cela empêche les E / S bloquantes de bloquer le reste des événements dans la file d'attente d'événements.
la source
Il n'y a qu'une seule boucle d'événements fournie par libuv, V8 n'est qu'un moteur d'exécution JS.
la source
En tant que débutant en javascript, j'avais également le même doute, NodeJS contient-il 2 boucles d'événements?. Après de longues recherches et discussions avec l'un des contributeurs de V8, j'ai obtenu les concepts suivants.
la source
La
pbkdf2
fonction a l'implémentation JavaScript mais elle délègue en fait tout le travail à faire du côté C ++.ressource: https://github.com/nodejs/node/blob/master/src/node_crypto.cc
Le module Libuv a une autre responsabilité qui est pertinente pour certaines fonctions très particulières de la bibliothèque standard.
Pour certains appels de fonction de bibliothèque standard, le côté Node C ++ et Libuv décident de faire des calculs coûteux en dehors de la boucle d'événements entièrement.
Au lieu de cela, ils utilisent quelque chose appelé pool de threads, le pool de threads est une série de quatre threads qui peuvent être utilisés pour exécuter des tâches coûteuses en calcul telles que la
pbkdf2
fonction.Par défaut, Libuv crée 4 threads dans ce pool de threads.
En plus des threads utilisés dans la boucle d'événements, il existe quatre autres threads qui peuvent être utilisés pour décharger les calculs coûteux qui doivent se produire dans notre application.
De nombreuses fonctions incluses dans la bibliothèque standard Node utilisent automatiquement ce pool de threads. La
pbkdf2
fonction étant l'une d'entre elles.La présence de ce pool de threads est très significative.
Node n'est donc pas vraiment à thread unique, car il existe d'autres threads que Node utilise pour effectuer des tâches coûteuses en calcul.
Si le pool d'événements était responsable de la tâche coûteuse en calcul, notre application Node ne pourrait rien faire d'autre.
Notre CPU exécute toutes les instructions dans un thread une par une.
En utilisant le pool de threads, nous pouvons faire d'autres choses dans une boucle d'événements pendant que les calculs sont en cours.
la source