Il semble que certaines des entités discutées (ex : libev etc.) aient perdu de leur pertinence, du fait que cela fait un moment, mais je pense que la question a encore un grand potentiel.
Je vais essayer d'expliquer le fonctionnement du modèle piloté par les événements à l'aide d'un exemple abstrait, dans un environnement UNIX abstrait, dans le contexte de Node, à ce jour.
Le point de vue du programme :
- Le moteur script lance l'exécution du script.
- Chaque fois qu'une opération liée au CPU est rencontrée, elle est exécutée en ligne (machine réelle), dans son intégralité.
- Chaque fois qu'une opération liée aux E/S est rencontrée, la demande et son gestionnaire d'achèvement sont enregistrés dans une "machine à événements" (machine virtuelle).
- Répétez les opérations de la même manière ci-dessus jusqu'à ce que le script se termine. Opération liée au CPU - exécuter en ligne, celles liées aux E/S, demander à la machinerie comme ci-dessus.
- Lorsque les E/S sont terminées, les auditeurs sont rappelés.
La machinerie événementielle ci-dessus s'appelle libuv AKA event loop framework. Node exploite cette bibliothèque pour mettre en œuvre son modèle de programmation piloté par les événements.
Le point de vue du nœud :
- Un seul thread pour héberger le runtime.
- Récupérer le script de l'utilisateur.
- Compilez-le en natif [levier v8]
- Chargez le binaire, et sautez dans le point d'entrée.
- Le code compilé exécute les activités liées au CPU en ligne, en utilisant des primitives de programmation.
- De nombreux codes liés aux entrées/sorties et aux temporisateurs ont des enveloppes natives. Par exemple, les entrées/sorties réseau.
- Les appels d'E/S sont donc acheminés du script vers les ponts C++, avec le handle d'E/S et le gestionnaire d'achèvement passés comme arguments.
- Le code natif exerce la boucle libuv. Il acquiert la boucle, met en file d'attente un événement de bas niveau qui représente l'E/S, et un wrapper de callback natif dans la structure de la boucle libuv.
- Le code natif retourne au script - aucune E/S n'a lieu pour le moment !
- Les points ci-dessus sont répétés plusieurs fois, jusqu'à ce que tout le code non-I/O soit exécuté, et que tout le code I/O soit enregistré dans la libuv.
- Enfin, quand il n'y a plus rien à exécuter dans le système, le nœud passe le contrôle à la libuv
- libuv entre en action, il récupère tous les événements enregistrés, interroge le système d'exploitation pour obtenir leur exploitabilité.
- Ceux qui sont prêts pour les E/S dans un mode non bloquant, sont récupérés, les E/S effectuées et leurs rappels émis. L'un après l'autre.
- Celles qui ne sont pas encore prêtes (par exemple une lecture de socket, pour laquelle l'autre point d'extrémité n'a encore rien écrit) continueront d'être sondées par le système d'exploitation jusqu'à ce qu'elles soient disponibles.
- La boucle maintient en interne une minuterie toujours croissante. Lorsque l'application demande un rappel différé (comme setTimeout), la valeur de cette minuterie interne est utilisée pour calculer le bon moment pour lancer le rappel.
Si 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 du réseau peuvent attendre dans l'attente d'un événement externe, tel que la réponse de l'autre extrémité avec des données, etc. Par exemple, si vous ouvrez un fichier et attendez que le fd soit prêt avec des données, cela ne se produira pas, car personne n'est en train de lire ! Dans le même temps, si vous lisez le fichier en ligne dans le thread principal, cela peut potentiellement bloquer d'autres activités dans le programme, et peut créer des problèmes visibles, car les opérations de fichiers sont très lentes par rapport aux activités liées au processeur. Ainsi, des threads internes (configurables par la variable d'environnement UV_THREADPOOL_SIZE) sont utilisés pour opérer sur les fichiers, tandis que l'abstraction événementielle fonctionne intacte, du point de vue du programme.
J'espère que cela vous aidera.