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


Answers

Par Thomas Marquadt de l'équipe ASP.NET chez Microsoft, il est sûr d'utiliser le ASP.NET ThreadPool (QueueUserWorkItem).

De l'article :

Q) Si mon application ASP.NET utilise des threads CLR ThreadPool, ne vais-je pas affamer ASP.NET, qui utilise également le ThreadPool CLR pour exécuter des requêtes? Blockquote

A) [T] o résumer, ne vous inquiétez pas de affamer ASP.NET de threads, et si vous pensez qu'il y a un problème ici, faites le moi savoir et nous nous en occuperons.

Q) Dois-je créer mes propres threads (nouveau thread)? Ce ne sera pas mieux pour ASP.NET, car il utilise le CLR ThreadPool.

A) S'il vous plaît ne le faites pas. Ou pour le dire autrement, non !!! Si vous êtes vraiment intelligent - beaucoup plus intelligent que moi - alors vous pouvez créer vos propres fils; Sinon, n'y pense même pas. Voici quelques raisons pour lesquelles vous ne devriez pas créer fréquemment de nouveaux threads:

1) C'est très cher, comparé à QueueUserWorkItem ... En passant, si vous pouvez écrire un meilleur ThreadPool que les CLR, je vous encourage à postuler pour un emploi chez Microsoft, car nous recherchons des gens comme vous! .

Question

J'ai toujours eu l'impression que l'utilisation du ThreadPool pour des tâches d'arrière-plan éphémères (disons non critiques) était considérée comme la meilleure pratique, même dans ASP.NET, mais je suis tombé sur cet article qui semble suggérer le contraire - le L'argument étant que vous devriez quitter ThreadPool pour traiter les requêtes liées à ASP.NET.

Alors voici comment j'ai fait de petites tâches asynchrones jusqu'à maintenant:

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

Et l'article suggère plutôt de créer un thread explicitement, similaire à:

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

La première méthode a l'avantage d'être gérée et limitée, mais il y a le potentiel (si l'article est correct) que les tâches en arrière-plan se disputent les threads avec les gestionnaires de requêtes ASP.NET. La deuxième méthode libère le ThreadPool, mais au prix d'être illimité et donc potentiellement utiliser trop de ressources.

Donc ma question est, le conseil dans l'article est-il correct?

Si votre site recevait tellement de trafic que votre ThreadPool était plein, alors il vaut mieux sortir de bande, ou bien un ThreadPool complet impliquerait que vous atteignez la limite de vos ressources de toute façon, auquel cas vous ne devrait pas essayer de démarrer vos propres discussions?

Clarification: Je demande simplement dans le cadre de petites tâches asynchrones non-critiques (par exemple, la journalisation à distance), des éléments de travail pas chers qui nécessiteraient un processus séparé (dans ces cas, je suis d'accord, vous aurez besoin d'une solution plus robuste).




On m'a posé une question similaire au travail la semaine dernière et je vais vous donner la même réponse. Pourquoi utilisez-vous plusieurs applications Web à la demande? Un serveur Web est un système fantastique optimisé pour fournir de nombreuses requêtes en temps opportun (c'est-à-dire multi-threading). Pensez à ce qui se passe lorsque vous demandez presque n'importe quelle page sur le Web.

  1. Une demande est faite pour une page
  2. Le code HTML est servi
  3. Le Html dit au client de faire d'autres requets (js, css, images, etc.)
  4. De plus amples informations sont fournies

Vous donnez l'exemple de la journalisation à distance, mais cela devrait être une préoccupation de votre enregistreur. Un processus asynchrone devrait être en place pour recevoir les messages en temps opportun. Sam signale même que votre enregistreur (log4net) devrait déjà supporter cela.

Sam a également raison de dire que l'utilisation du pool de threads sur le CLR ne provoquera pas de problèmes avec le pool de threads dans IIS. La chose à laquelle il faut se préoccuper ici, c'est que vous ne générez pas de threads à partir d'un processus, vous générez de nouveaux threads à partir de threads IIS. Il y a une différence et la distinction est importante.

Threads vs processus

Les threads et les processus sont des méthodes de parallélisation d'une application. Toutefois, les processus sont des unités d'exécution indépendantes qui contiennent leurs propres informations d'état, utilisent leurs propres espaces d'adressage et n'interagissent que par le biais de mécanismes de communication interprocessus (généralement gérés par le système d'exploitation). Les applications sont généralement divisées en processus au cours de la phase de conception, et un processus maître génère automatiquement des sous-processus lorsqu'il est judicieux de séparer logiquement des fonctionnalités applicatives significatives. En d'autres termes, les processus sont une construction architecturale.

En revanche, un thread est une construction de codage qui n'affecte pas l'architecture d'une application. Un seul processus peut contenir plusieurs threads; tous les threads d'un processus partagent le même état et le même espace mémoire et peuvent communiquer directement entre eux, car ils partagent les mêmes variables.

Source




Cet article n'est pas correct. ASP.NET possède son propre pool de threads, threads de travail gérés, pour traiter les requêtes ASP.NET. Ce pool contient généralement quelques centaines de threads et est séparé du pool ThreadPool, qui est un multiple plus petit de processeurs.

L'utilisation de ThreadPool dans ASP.NET n'interfère pas avec les threads de travail ASP.NET. L'utilisation de ThreadPool est correcte.

Il serait également acceptable d'installer un seul thread qui est juste pour la journalisation des messages et en utilisant le modèle producteur / consommateur pour transmettre les messages de journaux à ce thread. Dans ce cas, puisque le thread est de longue durée, vous devez créer un nouveau thread unique pour exécuter la journalisation.

Utiliser un nouveau fil pour chaque message est définitivement exagéré.

Une autre alternative, si vous ne parlez que de la journalisation, est d'utiliser une bibliothèque comme log4net. Il gère la journalisation dans un thread séparé et prend en charge tous les problèmes de contexte qui pourraient survenir dans ce scénario.




Si IIS utilise le même ThreadPool pour gérer les demandes entrantes semble difficile d'obtenir une réponse définitive à, et semble également avoir changé au fil des versions. Il semblerait donc judicieux de ne pas trop utiliser les threads ThreadPool, de sorte qu'IIS en ait beaucoup. D'un autre côté, engendrer son propre fil pour chaque petite tâche semble être une mauvaise idée. Vraisemblablement, vous avez une sorte de verrouillage dans votre journalisation, de sorte qu'un seul thread pourrait progresser à la fois, et le reste serait juste à tour de rôle programmé et non programmé (sans parler de la surcharge de générer un nouveau thread). Essentiellement, vous rencontrez les problèmes précis que le ThreadPool a été conçu pour éviter.

Il semble qu'un compromis raisonnable serait pour votre application d'allouer un seul thread de consignation auquel vous pourriez passer des messages. Vous devriez faire attention à ce que l'envoi de messages soit aussi rapide que possible afin que vous ne ralentissiez pas votre application.




Je pense définitivement que la pratique générale pour le travail asynchrone rapide et de faible priorité dans ASP.NET consisterait à utiliser le pool de threads .NET, en particulier pour les scénarios à fort trafic, car vous voulez que vos ressources soient limitées.

De plus, l'implémentation du thread est cachée - si vous lancez vos propres threads, vous devez les gérer correctement. Ne pas dire que vous ne pouviez pas le faire, mais pourquoi réinventer cette roue?

Si la performance devient un problème et que vous pouvez déterminer que le pool de threads est le facteur limitant (et non les connexions à la base de données, les connexions réseau sortantes, la mémoire, les délais d'attente, etc.) , etc.

Si vous ne rencontrez pas de problème de performance, le choix de générer de nouveaux threads pour réduire les conflits avec la file d'attente de requêtes ASP.NET est une optimisation prématurée classique.

Idéalement, vous n'avez pas besoin d'utiliser un thread séparé pour effectuer une opération de journalisation. Il vous suffit d'activer le thread d'origine pour terminer l'opération le plus rapidement possible, où MSMQ et un thread / processus distinct entrent dans l'image. 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'une file d'attente partagée en mémoire va rapidement épuiser son accueil.




Links