Le style asynchrone inhérent à la programmation monothread et à la fonction de rappel dans node.js nous rend parfois heureux et parfois inquiets. Parlons d’abord du monothreading. Beaucoup de gens se demandent comment le monothread de node.js peut atteindre une simultanéité élevée ? Cette question n’est pas l’objet de cet article, alors arrêtons-nous là. Pour clarifier, le thread unique de node.js fait uniquement référence au moteur JavaScript monothread. Dans tous les cas, nous n'avons aucun moyen d'implémenter le multi-threading et le blocage en JavaScript (la méthode utilisée dans cet article n'est pas non plus synchronisée via le). Moteur V8); mais pour le nœud. D'autres aspects de .js ne signifient pas qu'il ne peut pas être multithread, comme IO. Si node.js est maintenant soumis à un grand nombre de requêtes et que ces requêtes sont gourmandes en E/S, alors chaque fois que le nœud accepte une requête, le thread javascript n'attendra pas toujours ici lorsqu'il rencontrera une longue opération d'E/S. Au lieu de cela, il passera le contrôle et. ajoutez les opérations à effectuer une fois l'opération IO terminée dans la pile de rappel (lorsqu'il y a trop de niveaux de rappel et que le nombre d'accès est trop grand, un grand nombre de chaînes de rappel peuvent faire éclater la pile). Pendant ce temps, node.js peut gérer d'autres requêtes. Ainsi, pour node.js, bien que javascript soit monothread et ne puisse traiter qu'une seule requête à la fois, le temps nécessaire à javascript pour traiter une requête est souvent plus court (pour les applications gourmandes en E/S). de manière asynchrone, puis pendant le traitement, cette requête libérera le contrôle, permettant à node.js de gérer d'autres requêtes. Au cours de cette requête simultanée, les IO sont en fait toujours dans un état concurrent, ce qui réduit le nombre de threads traitant les requêtes et économise des ressources pour augmenter le nombre de threads IO pour les requêtes gourmandes en IO qui prennent généralement beaucoup de temps, cela apportera sans aucun doute des améliorations de performances. . promouvoir.
J'ai mis l'accent sur l'intensité des IO dans le passé, mais j'insiste en fait sur les points forts de node.js. En conséquence, son inconvénient réside dans les requêtes gourmandes en CPU. La raison est très simple, JavaScript ne sera pas simultané et les autres requêtes ne pourront être traitées qu'une fois qu'une requête sera terminée. Plus le traitement d’une demande est long, plus les autres demandes doivent attendre. Une seule requête sera traitée en même temps et les performances de concurrence sont très faibles.
Cela dit, je tiens à être clair : node.js ne doit pas être bloqué ; les méthodes qui peuvent être traitées de manière asynchrone sont traitées de manière asynchrone (comme l'utilisation de fs.readFile() au lieu de fs.syncReadFile() fs.readFileSync () méthode) .
Ne peut pas être bloqué dans le nœud, ne signifie pas qu'il ne peut pas être bloqué en dehors du nœud. Nous avons parlé des fibres plus tôt, essayons maintenant d'implémenter le blocage dans les fibres. Prenons comme exemple le traitement d'une requête http :
yield() et run(), veuillez vérifier "fibres dans le nœud" par vous-même.
Les fibres ne fonctionnent pas dans le processus du nœud, donc le blocage au sein des fibres n'a aucun impact sur les performances globales du nœud. Et c'est assez simple à mettre en œuvre. Il vous suffit de céder la fibre lorsque vous souhaitez bloquer. Si vous devez continuer à fonctionner, exécutez run() pour restaurer la fibre. Dans l'exemple ci-dessus, nous souhaitons bloquer le programme en cours lorsque la requête http.get est lancée et reprendre le programme lorsque toutes les réceptions de données sont terminées. Nous utilisons donc Fiber.yield() pour interrompre cette fibre après avoir appelé http.get. Lors de la surveillance de la réponse, si l'événement de fin est déclenché, cela indique que la transmission des données est terminée, donc dans la fonction de rappel de fin, appelez Fiber.current.run() pour restaurer la fibre. De cette façon, le code suivant sera obtenu. http.get de manière synchrone. Données demandées.
L'exemple ci-dessus est juste pour donner une idée. Si vous faites une encapsulation abstraite de cette idée, par exemple, effectuez un curry en une étape sur une méthode asynchrone qui accepte une fonction de rappel comme paramètre, interrompez-la après l'appel et détournez la fonction de rappel pour restaurer le code du programme comme rappel fonction. Après avoir obtenu les données asynchrones, le programme déclenche la fonction de rappel prédéterminée, qui peut essentiellement réaliser la synchronisation de la méthode asynchrone. Ce paragraphe est assez déroutant, mais il s'agit essentiellement de l'idée d'implémentation de fibres/future. Si vous êtes intéressé, veuillez vous référer à son code source.