J'écris un serveur et j'envoie chaque action de dans un thread séparé lorsque la demande est reçue. Je le fais parce que presque chaque demande fait une requête de base de données. J'utilise une bibliothèque de threadpool pour réduire la construction / destruction des threads.
Ma question est: quel est un bon point de coupure pour les threads d'E / S comme ceux-ci? Je sais que ce ne serait qu'une estimation approximative, mais parlons-nous de centaines? Milliers?
Comment pourrais-je déterminer ce que serait cette coupure?
ÉDITER:
Merci à tous pour vos réponses, il semble que je vais juste devoir le tester pour connaître mon plafond de nombre de threads. La question est cependant: comment savoir si j'ai atteint ce plafond? Que dois-je mesurer exactement?
Réponses:
Certaines personnes diraient que deux fils, c'est trop - je ne suis pas tout à fait dans ce camp :-)
Voici mon conseil: mesurez, ne devinez pas. Une suggestion est de le rendre configurable et de le régler initialement sur 100, puis de libérer votre logiciel à l'état sauvage et de surveiller ce qui se passe.
Si votre utilisation de thread atteint un pic à 3, alors 100 est trop. S'il reste à 100 pendant la majeure partie de la journée, augmentez-le jusqu'à 200 et voyez ce qui se passe.
Vous pourriez en fait avoir votre code lui-même surveiller l'utilisation et ajuster la configuration pour le prochain démarrage, mais c'est probablement exagéré.
Pour clarification et élaboration:
Je ne préconise pas de rouler votre propre sous-système de pool de threads, utilisez certainement celui que vous avez. Mais, puisque vous posiez des questions sur un bon point de coupure pour les threads, je suppose que votre implémentation de pool de threads a la capacité de limiter le nombre maximum de threads créés (ce qui est une bonne chose).
J'ai écrit du code de regroupement de connexions de threads et de bases de données et ils ont les fonctionnalités suivantes (qui, selon moi, sont essentielles pour les performances):
Le premier définit une ligne de base pour des performances minimales en termes de client de pool de threads (ce nombre de threads est toujours disponible pour utilisation). Le second définit une restriction sur l'utilisation des ressources par les threads actifs. Le troisième vous ramène à la ligne de base en temps calme afin de minimiser l'utilisation des ressources.
Vous devez équilibrer l'utilisation des ressources d'avoir des threads inutilisés (A) contre l'utilisation des ressources de ne pas avoir suffisamment de threads pour effectuer le travail (B).
(A) correspond généralement à l'utilisation de la mémoire (piles, etc.), car un thread qui ne fonctionne pas n'utilisera pas une grande partie du processeur. (B) sera généralement un retard dans le traitement des demandes à mesure qu'elles arrivent, car vous devez attendre qu'un thread soit disponible.
Voilà pourquoi vous mesurez. Comme vous le dites, la grande majorité de vos threads attendront une réponse de la base de données pour ne pas s'exécuter. Il y a deux facteurs qui affectent le nombre de threads que vous devez autoriser.
Le premier est le nombre de connexions DB disponibles. Cela peut être une limite stricte sauf si vous pouvez l'augmenter au niveau du SGBD - je vais supposer que votre SGBD peut prendre un nombre illimité de connexions dans ce cas (bien que vous devriez idéalement mesurer cela également).
Ensuite, le nombre de threads que vous devriez avoir dépend de votre utilisation historique. Le minimum que vous devriez avoir en cours d'exécution est le nombre minimum que vous avez déjà eu en cours d'exécution + A%, avec un minimum absolu de (par exemple, et le rendre configurable comme A) 5.
Le nombre maximal de threads doit être votre maximum historique + B%.
Vous devez également surveiller les changements de comportement. Si, pour une raison quelconque, votre utilisation atteint 100% de la disponibilité pendant un temps significatif (de sorte que cela affecterait les performances des clients), vous devriez augmenter le maximum autorisé jusqu'à ce qu'il soit à nouveau B% plus élevé.
En réponse au "que dois-je mesurer exactement?" question:
Ce que vous devez mesurer spécifiquement, c'est la quantité maximale de threads en utilisation simultanée (par exemple, en attente d'un retour de l'appel DB) sous charge. Ajoutez ensuite un facteur de sécurité de 10% par exemple (souligné, car d'autres affiches semblent prendre mes exemples comme des recommandations fixes).
De plus, cela doit être fait dans l'environnement de production pour le réglage. Il est normal d'obtenir une estimation au préalable, mais vous ne savez jamais quelle production va vous lancer (c'est pourquoi toutes ces choses devraient être configurables au moment de l'exécution). Il s'agit d'attraper une situation telle qu'un doublement inattendu des appels clients entrant.
la source
Cette question a été discutée de manière assez approfondie et je n'ai pas eu la chance de lire toutes les réponses. Mais voici quelques éléments à prendre en considération lors de l'examen de la limite supérieure du nombre de threads simultanés qui peuvent coexister pacifiquement dans un système donné.
Vous pouvez maintenant ajuster la taille de votre pile pour incorporer plus de threads, mais vous devez ensuite prendre en compte les frais généraux de gestion des threads (création / destruction et planification). Vous pouvez appliquer l'affinité CPU à un processus donné ainsi qu'à un thread donné pour les lier à des CPU spécifiques afin d'éviter les frais généraux de migration de threads entre les CPU et d'éviter les problèmes de trésorerie.
Notez que l'on peut créer des milliers de threads à sa guise, mais lorsque Linux manque de VM, il commence juste à tuer des processus au hasard (donc des threads). C'est pour éviter que le profil de l'utilitaire ne soit optimisé. (La fonction utilitaire indique l'utilité à l'échelle du système pour une quantité donnée de ressources. Avec des ressources constantes dans ce cas, Cycles CPU et mémoire, la courbe d'utilité s'aplatit avec de plus en plus de tâches).
Je suis sûr que le planificateur du noyau Windows fait quelque chose de ce genre pour gérer la surutilisation des ressources
[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/
la source
Si vos threads effectuent tout type de travail gourmand en ressources (CPU / disque), vous verrez rarement des avantages au-delà d'un ou deux, et un trop grand nombre réduira les performances très rapidement.
Le `` meilleur des cas '' est que vos derniers threads se bloqueront pendant que les premiers se termineront, ou certains auront des blocs à faible surcharge sur les ressources à faible conflit. Le pire des cas est que vous commencez à écraser le cache / disque / réseau et votre débit global chute à travers le sol.
Une bonne solution consiste à placer des demandes dans un pool qui sont ensuite envoyées aux threads de travail à partir d'un pool de threads (et oui, éviter la création / destruction continue de threads est une excellente première étape).
Le nombre de threads actifs dans ce pool peut ensuite être modifié et mis à l'échelle en fonction des résultats de votre profilage, du matériel sur lequel vous exécutez et d'autres choses qui peuvent se produire sur la machine.
la source
Une chose que vous devez garder à l'esprit est que python (au moins la version basée sur C) utilise ce qu'on appelle un verrou d'interpréteur global qui peut avoir un impact énorme sur les performances sur les machines multicœurs.
Si vous avez vraiment besoin de tirer le meilleur parti du python multithread, vous voudrez peut-être envisager d'utiliser Jython ou quelque chose.
la source
Comme l'a dit à juste titre Pax, mesurez, ne devinez pas . C'est ce que j'ai fait pour DNSwitness et les résultats ont été surprenants: le nombre idéal de threads était beaucoup plus élevé que je ne le pensais, quelque chose comme 15 000 threads pour obtenir les résultats les plus rapides.
Bien sûr, cela dépend de beaucoup de choses, c'est pourquoi vous devez vous mesurer.
Mesures complètes (en français seulement) dans Combien de fils d'exécution? .
la source
J'ai écrit un certain nombre d'applications fortement multi-thread. J'autorise généralement le nombre de threads potentiels à être spécifié par un fichier de configuration. Lorsque j'ai réglé pour des clients spécifiques, j'ai défini un nombre suffisamment élevé pour que mon utilisation de tous les cœurs de processeur soit assez élevée, mais pas si élevée que j'ai rencontré des problèmes de mémoire (il s'agissait de systèmes d'exploitation 32 bits au temps).
Autrement dit, une fois que vous avez atteint un goulot d'étranglement, que ce soit le processeur, le débit de la base de données, le débit du disque, etc., l'ajout de threads n'augmentera pas les performances globales. Mais jusqu'à ce que vous atteigniez ce point, ajoutez plus de discussions!
Notez que cela suppose que le ou les systèmes en question sont dédiés à votre application et que vous n'avez pas besoin de bien jouer (évitez de mourir de faim) d'autres applications.
la source
La réponse "Big Iron" est généralement un thread par ressource limitée - processeur (lié au CPU), armé (lié aux E / S), etc. - mais cela ne fonctionne que si vous pouvez acheminer le travail vers le thread approprié pour la ressource. être accessible.
Lorsque cela n'est pas possible, considérez que vous disposez de ressources fongibles (CPU) et de ressources non fongibles (bras). Pour les processeurs, il n'est pas essentiel d'attribuer chaque thread à un processeur spécifique (bien que cela aide à la gestion du cache), mais pour les bras, si vous ne pouvez pas affecter un thread au bras, vous entrez dans la théorie de la file d'attente et quel est le nombre optimal pour garder les bras occupé. En général, je pense que si vous ne pouvez pas acheminer les demandes en fonction du bras utilisé, alors avoir 2-3 threads par bras sera à peu près correct.
Une complication survient lorsque l'unité de travail transmise au thread n'exécute pas une unité de travail raisonnablement atomique. Par exemple, vous pouvez avoir le thread à un moment donné accéder au disque, à un autre moment attendre sur un réseau. Cela augmente le nombre de «fissures» où des threads supplémentaires peuvent entrer et faire un travail utile, mais cela augmente également la possibilité pour les threads supplémentaires de polluer les caches les uns des autres, etc., et de bloquer le système.
Bien sûr, vous devez peser tout cela contre le «poids» d'un fil. Malheureusement, la plupart des systèmes ont des threads très lourds (et ce qu'ils appellent souvent des «threads légers» ne sont pas du tout des threads), il est donc préférable de se tromper sur le côté bas.
Ce que j'ai vu dans la pratique, c'est que des différences très subtiles peuvent faire une énorme différence dans le nombre de threads qui sont optimaux. En particulier, les problèmes de cache et les conflits de verrouillage peuvent limiter considérablement la quantité de simultanéité pratique.
la source
Une chose à considérer est le nombre de cœurs qui existent sur la machine qui exécutera le code. Cela représente une limite stricte sur le nombre de threads pouvant se poursuivre à un moment donné. Cependant, si, comme dans votre cas, les threads attendent fréquemment qu'une base de données exécute une requête, vous souhaiterez probablement ajuster vos threads en fonction du nombre de requêtes simultanées que la base de données peut traiter.
la source
Je pense que c'est un peu une esquive à votre question, mais pourquoi ne pas les fourrer dans les processus? Ma compréhension du réseautage (depuis les jours brumeux d'autrefois, je ne code pas vraiment les réseaux du tout) était que chaque connexion entrante peut être traitée comme un processus distinct, car si quelqu'un fait quelque chose de méchant dans votre processus, il ne le fait pas nuke l'ensemble du programme.
la source
ryeguy, je développe actuellement une application similaire et mon nombre de threads est réglé sur 15. Malheureusement si je l'augmente à 20, ça plante. Donc, oui, je pense que la meilleure façon de gérer cela est de mesurer si votre configuration actuelle autorise plus ou moins un certain nombre de threads.
la source
Dans la plupart des cas, vous devez autoriser le pool de threads à gérer cela. Si vous publiez du code ou donnez plus de détails, il pourrait être plus facile de voir s'il y a une raison pour laquelle le comportement par défaut du pool de threads ne serait pas le meilleur.
Vous pouvez trouver plus d'informations sur la façon dont cela devrait fonctionner ici: http://en.wikipedia.org/wiki/Thread_pool_pattern
la source
Autant de threads que de cœurs CPU est ce que j'ai entendu très souvent.
la source