113 votes

Utilisation de ThreadPool.QueueUserWorkItem dans ASP.NET dans un scénario à fort trafic

J'ai toujours eu l'impression que l'utilisation du pool de threads pour (disons non critique) de courte durée de tâches de fond a été considéré comme une bonne pratique, même dans ASP.NET mais puis je suis tombé sur cet article qui semble indiquer le contraire - l'argument étant que vous devez quitter le pool de threads pour traiter ASP.NET demandes connexes.

Voici donc comment j'ai été faire de petites tâches asynchrones jusqu'à présent:

ThreadPool.QueueUserWorkItem(s => PostLog(logEvent))

Et l'article est plutôt suggéré de créer un thread explicitement, similaires à:

new Thread(() => PostLog(logEvent)){ IsBackground = true }.Start()

La première méthode a l'avantage d'être géré et borné, mais il y a la possibilité (si l'article est correct) que les tâches en arrière-plan sont alors en lice pour les threads avec ASP.NET demande des gestionnaires. La deuxième méthode permet de libérer le pool de threads, mais au prix d'être illimitée, et donc la possibilité d'utiliser trop de ressources.

Donc ma question est, est les conseils donnés dans l'article correct?

Si votre site a été d'obtenir autant de trafic que votre pool de threads était plein, alors est-il préférable d'aller hors de la bande, ou un plein de pool de threads implique que vous êtes arriver à la limite de vos ressources de toute façon, dans ce cas, vous ne devriez pas essayer de démarrer votre propre fils?

Précisions: je suis juste de demander dans le champ d'application de petite taille non-critique tâches asynchrones (par exemple, la connexion à distance), pas cher éléments de travail qui nécessiterait un processus distinct (dans ces cas, je suis d'accord, vous aurez besoin d'une solution plus robuste).

106voto

Aaronaught Points 73049

D'autres réponses ici semblent être en laissant le point le plus important:

Sauf si vous essayez de paralléliser un CPU-intensive afin d'arriver plus vite sur une faible charge du site, il n'y a pas de point à l'aide d'un thread de travail.

Cela vaut pour les deux threads libres, créé en new Thread(...), et les threads de travail dans l' ThreadPool qui répondent à l' QueueUserWorkItem des demandes.

Oui, c'est vrai, vous pouvez mourir de faim l' ThreadPool dans un ASP.NET processus de mise en file d'attente trop d'éléments de travail. Elle permettra d'éviter ASP.NET de traitement des nouvelles demandes. Les informations contenues dans l'article est précis à cet égard; le même pool de threads utilisés pour QueueUserWorkItem est également utilisé pour traiter les requêtes.

Mais si vous êtes réellement files d'attente suffisamment d'éléments de travail à cause de cette famine, alors vous devriez mourir de faim, le pool de threads! Si vous exécutez littéralement des centaines de CPU-intensive opérations en même temps, à quoi bon faire pour avoir un autre thread de travail pour servir ASP.NET demande, lorsque la machine est déjà surchargé? Si vous êtes en cours d'exécution dans cette situation, vous avez besoin de redessiner complètement!

La plupart du temps je les voir ou de les entendre parler de multi-threaded code utilisé de façon inappropriée dans ASP.NET il n'est pas pour les les d'attente CPU-intensive de travail. C'est pour les les d'attente d'e/S de travail. Et si vous voulez faire des I/O de travail, alors vous devriez être en utilisant un thread d'e/S (I/O Port d'Achèvement).

Plus précisément, vous devriez être en utilisant la async rappels pris en charge par quoi que ce soit de la bibliothèque de la classe que vous utilisez. Ces méthodes sont toujours très clairement étiquetés; ils commencent avec les mots - Begin et End. Comme en Stream.BeginRead, Socket.BeginConnect, WebRequest.BeginGetResponse, et ainsi de suite.

Ces méthodes ne utiliser l' ThreadPool, mais ils utilisent IOCPs, qui ne pas interférer avec ASP.NET les demandes. Ils sont un type spécial de thread léger qui peut être "réveillé" par un signal d'interruption d'e/S du système. Et dans un ASP.NET application, vous avez normalement un thread d'e/S pour chaque thread de travail, de sorte que chaque demande unique peut avoir une opération asynchrone en file d'attente. C'est littéralement des centaines d'opérations asynchrones, sans une dégradation significative des performances (en supposant que l'I/O sous-système permet de conserver jusqu'). C'est beaucoup plus que vous aurez jamais besoin.

Il suffit de garder à l'esprit que async délégués ne fonctionnent pas de cette façon - ils vont finir par en utilisant un thread de travail, tout comme ThreadPool.QueueUserWorkItem. C'est seulement le haut-méthodes asynchrones de la .NET Framework bibliothèque de classes qui sont capables de faire cela. Vous pouvez le faire vous-même, mais c'est compliqué et un peu dangereux et probablement au-delà de la portée de cette discussion.

La meilleure réponse à cette question, à mon avis, est de ne pas utiliser l' ThreadPool ou un arrière-plan Thread instance dans ASP.NET. Ce n'est pas du tout comme filer un fil dans une application Windows Forms, où vous faire pour conserver l'INTERFACE utilisateur réactive et ne se soucient pas de la façon dont elle est efficace. Dans ASP.NET, votre préoccupation est le débit, et tout ce que la commutation de contexte sur tous les threads de travail est absolument va tuer votre débit si vous utilisez l' ThreadPool ou pas.

S'il vous plaît, si vous trouvez vous-même l'écriture de filetage code de ASP.NET - examiner si oui ou non il pourrait être réécrit pour utiliser les pré-existantes des méthodes asynchrones, et si il ne peut pas, alors s'il vous plaît examiner si oui ou non vous avez vraiment, vraiment besoin du code à exécuter dans un thread d'arrière-plan. Dans la majorité des cas, vous serez probablement en ajoutant de la complexité pour aucun bénéfice net.

46voto

Tim P. Points 1009

Par Thomas Marquadt de l'ASP.NET l'équipe de chez Microsoft, il est sûr à utiliser l'ASP.NET pool de threads (QueueUserWorkItem).

De l'article:

Q) Si mon ASP.NET l'Application utilise CLR pool de threads les threads, ne vais-je pas mourir de faim ASP.NET qui utilise aussi le CLR pool de threads pour exécuter les demandes? Blockquote

A) [T]o résumer, ne vous inquiétez pas mourir de faim ASP.NET de threads, et si vous pensez qu'il y a un problème ici, laissez - moi savoir et nous allons prendre soin d'elle.

Q) je dois créer mon propre fils (nouveau Thread)? Ce ne sera pas mieux pour ASP.NET puisqu'elle utilise le CLR ThreadPool.

A) s'il vous Plaît ne pas. Ou pour le dire d'une de manière différente, non!!! Si vous êtes vraiment smart-beaucoup plus intelligents que moi, alors vous pouvez créer votre propre fils; sinon, n'y pensez même pas. Voici quelques raisons pourquoi vous devriez pas souvent de créer de nouveaux threads:

1) Il est très coûteux, par rapport à QueueUserWorkItem...En passant, si vous pouvez écrire un meilleur pool de threads que le CLR, je vous encourage à postuler pour un emploi chez Microsoft, parce que nous sommes certainement à la recherche de gens comme vous!.

4voto

Noon Silk Points 30396

Les sites web ne devrait pas aller autour de la ponte des threads.

Généralement, vous déplacez cette fonctionnalité dans un Service Windows qui vous communiquent ensuite avec (j'utilise MSMQ pour parler).

-- Edit

J'ai décrit une mise en œuvre ici: http://stackoverflow.com/questions/1317641/queue-based-background-processing-in-asp-net-mvc-web-application

-- Edit

Pour élargir pourquoi c'est encore mieux que juste threads:

À l'aide de MSMQ, vous pouvez communiquer à un autre serveur. Vous pouvez écrire à une file d'attente à travers les machines, donc si vous de déterminer, pour une raison quelconque, que votre tâche en arrière-plan est d'utiliser les ressources du serveur principal trop, vous pouvez simplement déplacer assez trivialement.

Il vous permet également de lot-processus quelle que soit la tâche que vous étiez en train de faire (envoyer des e-mails/whatever).

4voto

Sam Points 3346

Je pense que la pratique générale pour rapide, de faible priorité asynchrone de travail dans ASP.NET serait d'utiliser l' .NET pool de threads, particulièrement pour les scénarios de trafic que vous voulez que vos ressources à être délimitée.

Aussi, la mise en œuvre de filetage est caché - si vous commencez frai votre propre fils, vous avez à les gérer correctement. Pas dire que vous ne pouvais pas le faire, mais pourquoi réinventer la roue?

Si la performance devient un problème, et vous pouvez établir que le pool de threads est le facteur limitant (et pas de connexions de base de données, sortant des connexions réseau, la mémoire, la page de délais d'attente, etc), puis de régler le pool de threads de configuration pour permettre à plus de threads de travail, la hausse des demandes en file d'attente, etc.

Si vous n'avez pas de problème de performance, puis en choisissant de frayer de nouvelles discussions afin de réduire les conflits avec les ASP.NET demande de la file d'attente est classique de l'optimisation prématurée.

Idéalement vous n'avez pas besoin d'utiliser un thread séparé pour effectuer une opération d'enregistrement si - il vous suffit d'activer le thread d'origine pour terminer l'opération le plus rapidement possible, qui est l'endroit où MSMQ et un autre thread consommateur / processus entrent en jeu. Je suis d'accord que c'est plus lourd et plus de travail à mettre en œuvre, mais vous avez vraiment besoin de la durabilité ici - la volatilité d'un partagées, en mémoire de la file d'attente va rapidement porter ses de bienvenue.

2voto

Thomas Points 136

Vous devez utiliser QueueUserWorkItem, et éviter de créer de nouveaux threads comme vous le feriez pour éviter la peste. Pour un visuel qui explique pourquoi l'on ne meurt pas de faim ASP.NET puisqu'elle utilise le même pool de threads, imaginez un très habile jongleur à l'aide des deux mains pour garder une demi-douzaine de quilles, des épées, ou que ce soit en vol. Pour un visuel du pourquoi de la création de votre propre fils est mauvais, imaginer ce qui se passe à Seattle, à l'heure de pointe quand elle est fortement utilisée rampes d'accès à l'autoroute de permettre aux véhicules de s'engager dans la circulation immédiatement au lieu d'utiliser une lumière et de limiter le nombre d'entrées à un toutes les quelques secondes. Enfin, pour une explication plus détaillée, veuillez consulter ce lien:

http://blogs.msdn.com/tmarq/archive/2010/04/14/performing-asynchronous-work-or-tasks-in-asp-net-applications.aspx

Merci, Thomas

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X