Ces dernières années, le multi-cœur avec plusieurs cœurs montés sur un seul processeur est devenu courant. Cependant, avec le langage de programmation actuel, il est difficile pour les ingénieurs de créer des programmes multicœurs sans en être conscients. Par conséquent, je vais vous expliquer comment utiliser le multicœur à partir de différentes langues.
Un processus est un programme en cours d'exécution tel qu'une application, et un thread est une unité d'utilisation du processeur. Un processus a un ou plusieurs threads comme indiqué ci-dessous et peut traiter autant de threads que de cœurs de processeur. (Ces dernières années, [SMT](https://ja.wikipedia.org/wiki/%E5%90%8C%E6%99%82%E3%83%9E%E3%83%AB%E3%83% 81% E3% 82% B9% E3% 83% AC% E3% 83% 83% E3% 83% 87% E3% 82% A3% E3% 83% B3% E3% 82% B0) Le noyau peut gérer plusieurs threads, comme 2 threads. C'est comme 2 noyaux et 4 threads.) Afin d'utiliser efficacement le multicœur et d'exécuter un programme, il est nécessaire de générer un nombre approprié de threads côté programme pour le nombre de cœurs pouvant être traités par la CPU. Il est possible de créer plus de threads que le nombre de cœurs, mais le processeur ne peut traiter autant de threads qu'il y a de cœurs, et il existe un problème de ralentissement du traitement en raison du changement de thread à exécuter.
Il existe des termes similaires, parallèles et concurrents, mais ils sont différents. Parallèle est un cas où plusieurs processus sont traités en même temps et plusieurs threads sont traités par plusieurs cœurs. (Plusieurs processus ne peuvent pas être exécutés en même temps avec un seul cœur, donc le parallèle ne peut pas être réalisé.) Concurrent signifie que plusieurs processus sont commutés et exécutés en même temps, de sorte qu'un thread peut basculer et exécuter plusieurs processus. Puisqu'il est possible d'exécuter tout en commutant le traitement en plusieurs threads, il est également possible de réaliser des parallèles et des parallèles.
Apache, un serveur Web, utilise une méthode pour générer un processus pour chaque requête utilisateur, et lorsque le nombre de clients atteint environ 10 000, les performances de réponse diminuent considérablement même si les performances matérielles du serveur Web ont une marge. Un problème est survenu avec le C10K. (La cause spécifique du problème C10K était facile à comprendre dans cet article.) Par conséquent, dans nginx et Node.js, nous avons essayé de résoudre le problème C10K en traitant en parallèle en traitant les E / S asynchrones avec un seul thread.
Node.js Comme mentionné ci-dessus, Node.js fonctionne dans un seul thread, et l'approche consiste à effectuer un traitement en parallèle avec un traitement asynchrone tel que async / await. Comme le montre la figure ci-dessous, l'image est telle que lors de l'accès à une API externe, un autre traitement est effectué jusqu'à ce que le résultat soit renvoyé, et lorsque le résultat est obtenu, le traitement se poursuit. (Pour plus de détails, cet article était facile à comprendre.) Par conséquent, lors de l'exécution d'un traitement asynchrone standard, il n'est pas possible de faire ressortir les performances du multicœur. Par conséquent, dans Node.js, utilisez Cluster pour créer plusieurs processus (https://postd.cc/setting-up-a-node-js). Vous devez soit -cluster /), soit créer plusieurs threads à l'aide de worker_threads. Pour utiliser le cœur multicœur de cette manière, il est nécessaire de créer plusieurs processus ou threads du côté programme, et en multi-thread, vous pouvez partager la valeur des variables, mais en multi-processus, l'espace mémoire est séparé. [Avantages et inconvénients] de ne pas pouvoir partager la valeur des variables (https://stackoverflow.com/questions/56656498/how-is-cluster-and-worker-threads-work-in-node-js) Existe.
Dans Node.js, j'ai pu profiter du multicœur en créant plusieurs processus ou threads. Cependant, dans Ruby et Python, [Global Interpolator Lock (GIL)](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%BC%E3%83% 90% E3% 83% AB% E3% 82% A4% E3% 83% B3% E3% 82% BF% E3% 83% 97% E3% 83% AA% E3% 82% BF% E3% 83% AD% Il y a quelque chose appelé E3% 83% 83% E3% 82% AF), et même si vous créez plusieurs threads, ils ne peuvent pas être exécutés en parallèle. (Pour être exact, c'est le cas de CPython et CRuby implémentés en langage C, mais il est omis ici.) Par conséquent, si vous essayez de tirer parti du multi-cœur dans ces langages, cela ne peut pas être réalisé par le multi-threading et vous devez créer plusieurs processus.
Dans le langage Go, le traitement asynchrone est réalisé en parallèle et en parallèle en utilisant quelque chose appelé goroutine, et par défaut le nombre de cœurs de processeur est défini sur GOMAX PROCS
. Autant de threads que cette valeur sont préparés, et la goroutine de thread léger est exécutée dans les threads.
La figure ci-dessous est une image lorsque le nombre de cœurs de processeur est de 4 et GOMAX PROCS = 4
.
En utilisant goroutine de cette manière, vous pouvez exécuter des programmes en parallèle et en parallèle en tirant parti du multi-core.
(Pour la raison pour laquelle la goroutine est légère, cet article était facile à comprendre.)
Dans Rust, le traitement asynchrone peut être effectué en utilisant async / await. À ce stade, vous pouvez sélectionner la méthode d'allocation d'exécution pour les threads de traitement asynchrones en fonction du runtime utilisé. Un runtime populaire est tokio. Dans tokio, les threads sont créés pour le nombre de cœurs et le traitement asynchrone est passé à ces threads, ce qui est similaire à la façon dont goroutine utilise le multi-core. (Pour les autres méthodes d'allocation et le traitement asynchrone dans Rust, cet article était facile à comprendre. Surtout [À propos du modèle d'exécution ici](https://tech-blog.optim.co.jp/entry/2019/11/08/163000#%E5%AE%9F%E8%A1%8C%E3%83% A2% E3% 83% 87% E3% 83% AB) est facile à comprendre.)
En Ruby et Python, il est difficile de le rendre multi-thread en raison du mécanisme, et le traitement asynchrone de Node.js ne pouvait pas utiliser le multi-core tel quel. Cependant, dans le langage Go et Rust, qui sont populaires ces dernières années, en appelant le traitement asynchrone, le traitement parallèle et parallèle peut être effectué sans que l'ingénieur en soit conscient, et le multi-cœur peut être utilisé. Il est compréhensible que le langage Go et Rust soient populaires à l'ère actuelle, lorsque les processeurs multicœurs sont devenus monnaie courante.
[Illustration] Différences entre les cœurs de processeur, les threads et les processus, les commutateurs de contexte et le multi-threading Se rapprocher de la compréhension complète asynchrone Unity en connaissant la différence entre les processus, les threads et les tâches J'ai étudié les E / S asynchrones de Node.js Node.js je n'entends plus J'ai étudié GIL que vous devriez savoir si vous effectuez un traitement parallèle avec Python Pourquoi la goroutine est légère [Programmation asynchrone principale de Rust](https://tech-blog.optim.co.jp/entry/2019/11/08/163000#%E3%83%A9%E3%83%B3%E3%82 % BF% E3% 82% A4% E3% 83% A0% E3% 81% A7% E9% 9D% 9E% E5% 90% 8C% E6% 9C% 9F% E3% 82% BF% E3% 82% B9 % E3% 82% AF% E3% 82% 92% E8% B5% B7% E5% 8B% 95% E3% 81% 99% E3% 82% 8B)
Recommended Posts