Threads, un outil qui aide et devient indispensable au développement de solutions modernes et performantes. Quelle que soit la langue, la capacité d’effectuer des tâches en parallèle est très intéressante. Mais il y a évidemment la célèbre citation d'Oncle Ben : « Un grand pouvoir implique de grandes responsabilités. » Comment utiliser au mieux cette solution, en visant la performance, une meilleure utilisation des ressources et la santé des applications ? Tout d’abord, il est nécessaire de comprendre les concepts de base de ce sujet.
Les threads sont les unités de base d'exécution d'un processus dans un système d'exploitation. Ils permettent à un programme d'effectuer plusieurs opérations simultanément au sein du même processus. Chaque thread partage le même espace mémoire que le processus principal, mais peut s'exécuter indépendamment, ce qui est utile pour les tâches pouvant être effectuées en parallèle, telles que les opérations d'entrée/sortie (E/S), les calculs complexes ou les mises à jour de données. .
Sur de nombreux systèmes, les threads sont gérés par le système d'exploitation, qui alloue du temps CPU à chaque thread et gère le changement de contexte entre eux. Dans les langages de programmation comme Java, Python et C, il existe des bibliothèques et des frameworks qui facilitent la création et la gestion de threads.
Les threads sont principalement utilisés pour améliorer l'efficacité et la réactivité d'un programme. Les raisons d'utiliser les threads, en particulier en se concentrant sur le backend, sont :
Parallélisme : les threads vous permettent d'effectuer plusieurs opérations simultanément, en utilisant mieux les ressources CPU disponibles, en particulier sur les systèmes à plusieurs cœurs.
Performances : Dans les opérations d'E/S, telles que la lecture et l'écriture de fichiers ou la communication réseau, les threads peuvent aider à améliorer les performances en permettant au programme de continuer à effectuer d'autres tâches en attendant la fin de celles-ci. opérations.
Modularité : Les threads peuvent être utilisés pour diviser un programme en parties plus petites et plus gérables, chacune effectuant une tâche spécifique.
Cependant, il est important de gérer les threads avec soin, car une utilisation incorrecte peut entraîner des problèmes tels que des conditions de concurrence critique, des blocages et des difficultés de débogage. Pour une meilleure gestion de ceux-ci, une solution de pool de threads est utilisée.
Un pool de threads est un modèle de conception logicielle qui implique la création et la gestion d'un pool de threads pouvant être réutilisés pour effectuer des tâches. Au lieu de créer et de détruire à plusieurs reprises des threads pour chaque tâche, un pool de threads maintient un nombre fixe de threads prêts à exécuter des tâches selon les besoins. Cela peut améliorer considérablement les performances des applications qui doivent gérer de nombreuses tâches simultanées. Les points positifs de l'utilisation d'un pool de threads sont :
Performances améliorées : La création et la destruction de threads sont une opération coûteuse en termes de ressources. Un pool de threads minimise ce coût en réutilisant les threads existants.
Gestion des ressources : Contrôle le nombre de threads en cours d'exécution, évitant ainsi la création excessive de threads qui peuvent surcharger le système.
Facilité d'utilisation : Simplifie la gestion des threads, permettant aux développeurs de se concentrer sur la logique de l'application plutôt que sur la gestion des threads.
Évolutivité : Aide à faire évoluer les applications pour gérer efficacement un grand nombre de tâches simultanées.
Ok, bien sûr, je dois créer un pool de threads pour mieux utiliser cette fonctionnalité, mais une question qui revient rapidement est : "Combien de threads le pool doit-il contenir ?". Suivant la logique de base, plus on est de fous, non ? Si tout peut se faire en parallèle, cela ne tardera pas à se faire, car cela sera plus rapide. Il est donc préférable de ne pas limiter le nombre de threads, ni de définir un nombre élevé, afin que cela ne soit pas un problème. C'est vrai ?
C'est une déclaration juste, alors testons-la. Le code de ce test a été écrit en Kotlin uniquement pour plus de familiarité et de facilité d'écriture des exemples. Ce point est indépendant du langage.
4 exemples ont été réalisés en explorant différentes natures de systèmes. Les exemples 1 et 2 ont été réalisés pour utiliser le CPU, faire beaucoup de calculs, c'est-à-dire avoir un traitement massif. L'exemple 3 est axé sur les E/S, l'exemple étant une lecture d'un fichier et enfin, dans l'exemple 4 c'est une situation d'appels API en parallèle, se concentrant également sur les E/S. Ils ont tous utilisé des pools de tailles différentes, respectivement de 1, 2, 4, 8, 16, 32, 50, 100 et 500 threads. Tous les processus se produisent plus de 500 fois.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
1 2 3 4 5 6 7 8 9 |
|
Les exemples 1 à 3 ont un comportement commun, ils deviennent tous plus performants jusqu'à 8 threads, puis le temps de traitement augmente à nouveau, mais pas l'exemple 4, qu'est-ce que cela montre ? N'est-il pas intéressant de toujours utiliser le plus de fils de discussion possible ?
La réponse simple et rapide est non.
Le processeur de ma machine a 8 cœurs, c'est-à-dire qu'il peut effectuer 8 tâches en même temps, de plus le temps augmente à mesure que le temps de gestion des états de chaque thread finit par dégrader les performances.
Ok, cela répond aux exemples 1 à 3, mais qu'en est-il de l'exemple 4 ? Pourquoi les performances s’améliorent-elles à mesure que de threads sont lancés ?
Simple, comme il s'agit d'une intégration, la machine n'a aucun traitement, elle attend essentiellement une réponse, elle reste "en veille" jusqu'à ce que la réponse arrive, donc oui, ici le nombre de threads peut être plus grand. Mais attention, cela ne veut pas dire qu'il peut y en avoir le plus possible, les threads provoquent un épuisement des ressources, les utiliser sans discernement a un effet inverse qui affectera la santé globale du service.
Par conséquent, pour définir le nombre de threads dont disposera votre pool, le moyen le plus simple et le plus sûr est de séparer la nature de la tâche qui sera effectuée. Ils sont séparés en deux :
Tâches ne nécessitant pas de traitement :
Lorsque le type de tâche ne nécessite pas de traitement, plus de threads peuvent être créés qu'il n'y a de cœurs de processeur sur la machine. Cela se produit car il n'est pas nécessaire de traiter les informations pour terminer le thread, essentiellement les threads de cette nature attendent pour la plupart des réponses des intégrations, telles que l'écriture dans une base de données ou une réponse d'une API.
Tâches nécessitant un traitement :
Lorsque la solution comporte un traitement, c'est-à-dire que la machine effectue réellement un travail, le nombre maximum de threads doit être égal au nombre de cœurs du processeur de la machine. En effet, un cœur de processeur est incapable de faire plus d’une chose en même temps. Par exemple, si le processeur sur lequel la solution s'exécute possède 4 cœurs, alors votre pool de threads doit avoir la taille des cœurs de votre processeur, un pool de 4 threads.
Le premier point à définir lorsqu'on réfléchit à un pool de threads n'est pas forcément le nombre qui limitera sa taille, mais plutôt la nature de la tâche effectuée. Les threads aident beaucoup aux performances des services, mais ils doivent être utilisés de la meilleure façon possible afin qu'ils n'aient pas l'effet inverse et ne dégradent pas les performances, ou pire encore, n'affectent pas la santé de l'ensemble du service. Il est clair que les pools plus petits finissent par favoriser les tâches nécessitant beaucoup de traitement, en d’autres termes les tâches limitées par le processeur. Si vous n'êtes pas sûr que la solution dans laquelle les threads seront utilisés a un comportement dans lequel les traitements seront utilisés massivement, faites preuve de prudence, limitez votre pool au nombre de processeurs sur la machine, croyez-moi, cela économisera tu as beaucoup de maux de tête.
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!