Pourquoi disons-nous que Node.js n'est pas complètement monothread ? Comment comprendre ? L’article suivant en discutera avec vous, j’espère qu’il vous sera utile !
Je crois que tout le monde sait que node est un programme monothread qui utilise Event Loop pour obtenir plusieurs simultanéités. Malheureusement, ce n'est pas tout à fait exact.
Alors pourquoi Node.js n'est-il pas un programme entièrement monothread ?
Toutes les boucles Javsacript, V8 et d'événements que nous avons nous-mêmes écrites s'exécutent dans le même thread, qui est le thread principal.
Hé, cela ne signifie-t-il pas que ce nœud est monothread ?
Mais peut-être que vous ne savez pas que ce nœud contient de nombreux modules avec du code C++ derrière eux.
Bien que le nœud n'expose pas les utilisateurs à l'autorisation de contrôler les threads, C++ peut utiliser le multi-threading.
Alors, quand node utilisera-t-il le multi-threading ?
Si une méthode de nœud appelle la méthode synchronisation de C++ en arrière-plan, tout s'exécutera dans le thread principal.
Si une méthode de nœud appelle la méthode asynchrone de C++ en arrière-plan, parfois elle ne s'exécute pas dans le thread principal.
Talk n'est pas cher, montre-moi le code
Ici crypto
Modules associés, beaucoup sont écrits en C++. Le programme suivant est une fonction de calcul de hachage, généralement utilisée pour stocker les mots de passe.
import { pbkdf2Sync } from "crypto"; const startTime = Date.now(); let index = 0; for (index = 0; index < 3; index++) { pbkdf2Sync("secret", "salt", 100000, 64, "sha512"); const endTime = Date.now(); console.log(`${index} time, ${endTime - startTime}`); } const endTime = Date.now(); console.log(`in the end`);
Temps de sortie,
0 time, 44 1 time, 90 2 time, 134 in the end
peut être vu que cela prend environ 45 ms à chaque fois et que le code est exécuté séquentiellement sur le thread principal.
Faites attention à qui est le résultat final ? Notez qu'un hachage prend ici environ 45 ms sur mon processeur.
import { cpus } from "os"; import { pbkdf2 } from "crypto"; console.log(cpus().length); let startTime = console.time("time-main-end"); for (let index = 0; index < 4; index++) { startTime = console.time(`time-${index}`); pbkdf2("secret", `salt${index}`, 100000, 64, "sha512", (err, derivedKey) => { if (err) throw err; console.timeEnd(`time-${index}`); }); } console.timeEnd("time-main-end");
Le temps de sortie,
time-main-end: 0.31ms time-2: 45.646ms time-0: 46.055ms time-3: 46.846ms time-1: 47.159ms
Comme vous pouvez le voir ici, le thread principal se termine plus tôt, mais chaque temps de calcul est de 45 ms. Le processeur calcule le hachage. Le temps est de 45 ms. Le nœud ici utilise définitivement plusieurs threads pour le calcul du hachage.
Si je change le nombre d'appels ici à 10, alors le temps est le suivant. Vous pouvez voir qu'à mesure que le nombre de cœurs de processeur est utilisé, le temps augmente également. Une fois de plus, il est prouvé que le nœud utilise définitivement plusieurs threads pour le calcul du hachage.
time-main-end: 0.451ms time-1: 44.977ms time-2: 46.069ms time-3: 50.033ms time-0: 51.381ms time-5: 96.429ms // 注意这里,从第五次时间开始增加了 time-7: 101.61ms time-4: 113.535ms time-6: 121.429ms time-9: 151.035ms time-8: 152.585ms
Bien qu'il soit prouvé ici que le multi-threading est définitivement activé sur le nœud. Mais il y a un petit problème ? Le processeur de mon ordinateur est AMD R5-5600U, doté de 6 cœurs et 12 threads. Mais pourquoi le temps augmente-t-il à partir de la cinquième fois ? Le nœud n’utilise pas pleinement mon processeur ?
Quelle est la raison ?
Node utilise un pool de threads prédéfini. La taille par défaut de ce pool de threads est 4.
export UV_THREADPOOL_SIZE=6
Regardons un exemple,
import { request } from "https"; const options = { hostname: "www.baidu.com", port: 443, path: "/img/PC_7ac6a6d319ba4ae29b38e5e4280e9122.png", method: "GET", }; let startTime = console.time(`main`); for (let index = 0; index < 15; index++) { startTime = console.time(`time-${index}`); const req = request(options, (res) => { console.log(`statusCode: ${res.statusCode}`); console.timeEnd(`time-${index}`); res.on("data", (d) => { // process.stdout.write(d); }); }); req.on("error", (error) => { console.error(error); }); req.end(); } console.timeEnd("main");
main: 13.927ms time-2: 83.247ms time-4: 89.641ms time-3: 91.497ms time-12: 91.661ms time-5: 94.677ms ..... time-8: 134.026ms time-1: 143.906ms time-13: 140.914ms time-10: 144.088ms
Le programme principal ici est Cela s'est également terminé plus tôt. Ici, j'ai lancé la requête http pour télécharger des images 15 fois. Le temps nécessaire n'a pas augmenté de façon exponentielle et ne semblait pas être limité par le pool de threads/le processeur.
Pourquoi ? ? Node utilise-t-il un pool de threads ?
Si la méthode C++ asynchrone derrière Node, elle essaiera d'abord de voir s'il existe un support asynchrone du noyau. Par exemple, veuillez utiliser epoll (Linux) pour le réseau ici. Si le noyau ne fournit pas de méthode asynchrone, Node. utilisera son propre pool de threads. .
Ainsi, bien que la requête http soit asynchrone, elle est implémentée par le noyau lorsque le noyau est terminé, C++ en sera informé et C++ notifiera au thread principal de gérer le rappel.
Alors, quelles méthodes asynchrones dans Node utilisent le pool de threads ? Lesquels ne le feront pas ?
Native Kernal Async
Thread pool
C'est également le point d'entrée pour la plupart des optimisations de nœuds.
Mais comment ceux-ci se combinent-ils avec la boucle d'événement la plus importante ?
Je pense que tout le monde connaît très bien Event Loop. La boucle d'événements est comme un distributeur.
Si elle rencontre un programme javascript ordinaire ou un rappel, elle est transmise à V8 pour traitement.
Si vous rencontrez une méthode synchronisée écrite en C++, remettez-la en C++ et exécutez-la sur le thread principal.
Si vous rencontrez une méthode asynchrone, le verso est écrit en C++. S'il existe un support asynchrone du noyau, transmettez-le du thread principal au noyau pour traitement.
Si elle est asynchronele dos de la méthode est écrit en C++ S'il n'y a pas de support asynchrone par le noyau, elle est transmise du thread principal au pool de threads.
Le pool de threads et le noyau renverront les résultats à la boucle d'événements. Si un rappel javascript est enregistré, il sera transmis à la V8 pour traitement.
Ensuite, le cycle continue jusqu'à ce qu'il n'y ait plus rien à traiter.
Donc, Node n'est pas exactement un programme monothread.
Pour plus de connaissances sur les nœuds, veuillez visiter : tutoriel Nodejs !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!