Quand dois-je utiliser des contrôleurs asynchrones dans ASP.NET MVC?

216

J'ai quelques inquiétudes concernant l'utilisation des actions asynchrones dans ASP.NET MVC. Quand améliore-t-il les performances de mes applications et quand ne le fait-il pas ?

  1. Est-il bon d'utiliser l'action asynchrone partout dans ASP.NET MVC?
  2. Concernant les méthodes attendues: dois-je utiliser des mots clés asynchrones / attendre quand je veux interroger une base de données (via EF / NHibernate / autre ORM)?
  3. Combien de fois puis-je utiliser des mots clés en attente pour interroger la base de données de manière asynchrone dans une seule méthode d'action?
Vnuuk
la source

Réponses:

109

Les méthodes d' action asynchrone sont utiles lorsqu'une action doit effectuer plusieurs opérations indépendantes de longue durée.

Une utilisation typique de la classe AsyncController est les appels de service Web de longue durée.

Mes appels de base de données doivent-ils être asynchrones?

Le pool de threads IIS peut souvent gérer beaucoup plus de demandes de blocage simultanées qu'un serveur de base de données. Si la base de données est le goulot d'étranglement, les appels asynchrones n'accéléreront pas la réponse de la base de données. Sans mécanisme de limitation, la répartition efficace de plus de travail vers un serveur de base de données débordé à l'aide d'appels asynchrones déplace simplement une plus grande partie de la charge vers la base de données. Si votre base de données est le goulot d'étranglement, les appels asynchrones ne seront pas la solution miracle.

Vous devriez jeter un oeil à 1 et 2 références

Dérivé des commentaires @PanagiotisKanavos:

De plus, async ne signifie pas parallèle. L'exécution asynchrone libère un thread de pool de threads précieux du blocage pour une ressource externe, sans complexité ni coût de performance. Cela signifie que la même machine IIS peut gérer plus de demandes simultanées, pas qu'elle s'exécutera plus rapidement.

Vous devez également tenir compte du fait que les appels bloquants commencent par un spinwait gourmand en CPU. Pendant les périodes de stress, le blocage des appels entraînera une augmentation des retards et un recyclage du pool d'applications. Les appels asynchrones évitent simplement cela

Tharif
la source
27
En ce qui concerne async, IIS et la base de données, le blog est extrêmement ancien et les conclusions tirées ici sont fausses. IIS doit gérer une charge beaucoup plus importante que la base de données, les threads de pool de threads sont limités et une longue file d'attente de requêtes peut conduire à 500. Tout ce qui libère un thread en attendant les E / S est bénéfique. Même les liens ne concernent pas ce que le PO a demandé. En fait , les mêmes auteurs ont écrit que vous devez utiliser des méthodes asynchrones DB où vous pouvez
Panagiotis Kanavos
30
De plus, async ne signifie pas parallèle. L'exécution asynchrone libère un thread de pool de threads précieux du blocage pour une ressource externe, sans complexité ni coût de performance. Cela signifie que la même machine IIS peut gérer plus de demandes simultanées, pas qu'elle s'exécutera plus rapidement.
Panagiotis Kanavos
5
Vous devez également tenir compte du fait que les appels bloquants commencent par un spinwait gourmand en CPU. Pendant les périodes de stress, le blocage des appels entraînera une augmentation des retards et un recyclage du pool d'applications. Les appels asynchrones évitent tout simplement cela
Panagiotis Kanavos
1
Étant donné que c'est la réponse acceptée et donc au sommet pour la plupart des gens, il pourrait être judicieux de supprimer le deuxième premier paragraphe concernant les temps d'exécution et l'exécution en parallèle, ce qui n'a rien à voir avec async. Je me rends compte qu'il y a une note à la fin, mais elle est assez trompeuse.
Rob
1
L'exécution asynchrone ne libère un thread que dans les cas où il est vraiment asynchrone jusqu'au bas de l'implémentation et utilise un mécanisme de rappel pour signaler la disponibilité et faire tourner un nouveau thread pour changer de contexte et traiter le résultat. Donc, je ne sais pas dans quels cas ce changement de contexte / création de nouveaux threads est plus efficace que l'attente de résultats dans un seul thread? Les appels de service Web de longue durée sont de toute façon une mauvaise idée, je préfère le décharger sur un service d'arrière-plan fiable et laisser le client vérifier les résultats, qui peuvent arriver en quelques minutes, heures ou jours.
JustAMartin
229

Vous pouvez trouver mon article MSDN sur le sujet utile ; J'ai pris beaucoup d'espace dans cet article décrivant quand vous devez utiliser asyncsur ASP.NET, pas seulement comment utiliser asyncsur ASP.NET.

J'ai quelques inquiétudes concernant l'utilisation des actions asynchrones dans ASP.NET MVC. Quand cela améliore les performances de mes applications, et quand - non.

Tout d'abord, comprenez que async/ awaitconsiste à libérer des threads . Sur les applications GUI, il s'agit principalement de libérer le thread GUI afin que l'expérience utilisateur soit meilleure. Sur les applications serveur (y compris ASP.NET MVC), il s'agit principalement de libérer le thread de demande afin que le serveur puisse évoluer.

En particulier, il ne:

  • Faites vos demandes individuelles plus rapidement. En fait, ils termineront (juste un peu plus jeunes) plus lentement.
  • Revenez à l'appelant / navigateur lorsque vous appuyez sur un await. await"cède" uniquement au pool de threads ASP.NET, pas au navigateur.

La première question est - est-il bon d'utiliser l'action asynchrone partout dans ASP.NET MVC?

Je dirais qu'il est bon de l'utiliser partout où vous effectuez des E / S. Cependant, cela ne sera pas nécessairement bénéfique (voir ci-dessous).

Cependant, il est mauvais de l'utiliser pour les méthodes liées au processeur. Parfois, les développeurs pensent qu'ils peuvent obtenir les avantages asyncen appelant simplement Task.Runleurs contrôleurs, et c'est une idée horrible. Parce que ce code finit par libérer le thread de demande en prenant un autre thread, il n'y a donc aucun avantage (et en fait, ils subissent la pénalité des commutateurs de thread supplémentaires)!

Dois-je utiliser des mots clés asynchrones / attendre lorsque je souhaite interroger la base de données (via EF / NHibernate / autre ORM)?

Vous pouvez utiliser toutes les méthodes attendues dont vous disposez. À l'heure actuelle, la plupart des principaux acteurs soutiennent async, mais il y en a quelques-uns qui ne le font pas. Si votre ORM ne prend pas en charge async, n'essayez pas de l'envelopper Task.Runou quelque chose comme ça (voir ci-dessus).

Notez que j'ai dit "vous pouvez utiliser". Si vous parlez d'ASP.NET MVC avec un seul backend de base de données, vous n'obtiendrez (presque certainement) aucun avantage d'évolutivité async. En effet, IIS peut gérer beaucoup plus de demandes simultanées qu'une seule instance de SQL Server (ou tout autre SGBDR classique). Cependant, si votre backend est plus moderne - un cluster de serveurs SQL, Azure SQL, NoSQL, etc. - et que votre backend peut évoluer, et que votre goulot d'étranglement d'évolutivité est IIS, alors vous pouvez bénéficier d'un avantage d'évolutivité async.

Troisième question - Combien de fois puis-je utiliser des mots-clés en attente pour interroger la base de données de manière asynchrone dans UNE seule méthode d'action?

Autant que vous voulez. Cependant, notez que de nombreux ORM ont une règle d'une opération par connexion. En particulier, EF n'autorise qu'une seule opération par DbContext; cela est vrai que l'opération soit synchrone ou asynchrone.

Gardez également à l'esprit l'évolutivité de votre backend. Si vous utilisez une seule instance de SQL Server et que votre IIS est déjà capable de maintenir SQLServer à pleine capacité, doubler ou tripler la pression sur SQLServer ne vous aidera pas du tout.

Stephen Cleary
la source
2
@seebiscuit: Lors des E / S (asynchrones appropriées), aucun thread n'est utilisé. J'ai un article de blog qui va plus en détail.
Stephen Cleary du
2
Combien de requêtes IIS et une seule instance SQL Server peuvent-elles gérer? Comment puis-je trouver ces numéros?
MOD
1
@MOD: Cela dépend de la configuration et du matériel. La seule façon de trouver ces numéros est de faire un test de charge sur votre propre serveur.
Stephen Cleary
1
@Flezcano: méthodes qui s'exécutent entièrement sur le CPU. C'est-à-dire qu'ils ne font pas d'E / S ou de blocage.
Stephen Cleary
1
Désolé monsieur, mais n'accepterez donc PAS cette question de 2 lignes que j'essaie de comprendre. mettre en serveur chacune de ces mille requêtes ou devrais-je le faire asynchrone pour gérer 1000 requêtes?
Learning-Overthinker-Confused
21

est-il bon d'utiliser l'action asynchrone partout dans ASP.NET MVC?

Comme d'habitude en programmation, cela dépend . Il y a toujours un compromis quand on descend un certain chemin.

async-awaitbrille dans les endroits où vous savez que vous recevrez des demandes simultanées à votre service et que vous souhaitez pouvoir évoluer correctement. Comment async-awaitaide à évoluer? Dans le fait que lorsque vous appelez un appel d'E / S asynchrone de manière synchrone , tel qu'un appel réseau ou que vous frappez votre base de données, le thread actuel qui est responsable de l'exécution est bloqué en attendant la fin de la demande. Lorsque vous utilisezasync-await , vous activez le framework pour créer une machine d'état pour vous qui s'assure qu'après l'appel d'E / S est terminée, votre méthode continue de s'exécuter là où elle s'était arrêtée.

Une chose à noter est que cette machine d'état a une surcharge subtile. Rendre une méthode asynchrone ne la fait pas exécuter plus rapidement , et c'est un facteur important à comprendre et une idée fausse que beaucoup de gens ont.

Une autre chose à prendre en considération lors de l'utilisation async-awaitest le fait qu'elle est asynchrone tout le long , ce qui signifie que vous verrez l'async pénétrer toute votre pile d'appels, de haut en bas. Cela signifie que si vous souhaitez exposer des API synchrones, vous vous retrouverez souvent à dupliquer une certaine quantité de code, car l' async et la synchronisation ne se mélangent pas très bien.

Dois-je utiliser des mots clés asynchrones / attendre lorsque je souhaite interroger la base de données (via EF / NHibernate / autre ORM)?

Si vous choisissez de suivre le chemin de l'utilisation des appels d'E / S asynchrones, alors oui, async-await sera un bon choix, car de plus en plus de fournisseurs de bases de données modernes exposent la méthode asynchrone implémentant le TAP (Task Asynchronous Pattern).

Combien de fois puis-je utiliser des mots clés en attente pour interroger la base de données de manière asynchrone dans UNE seule méthode d'action?

Autant que vous le souhaitez, tant que vous suivez les règles énoncées par votre fournisseur de base de données. Il n'y a pas de limite au nombre d'appels asynchrones que vous pouvez effectuer. Si vous avez des requêtes indépendantes les unes des autres et pouvant être effectuées simultanément, vous pouvez effectuer une nouvelle tâche pour chacune et utiliser await Task.WhenAllpour attendre la fin des deux.

Yuval Itzchakov
la source
2
Les appels de base de données asynchrones ne s'exécutent pas plus rapidement mais permettent à la même machine IIS de traiter beaucoup plus de requêtes car les threads de pool de threads ne sont pas gaspillés. Cela réduit également les coûts du processeur car le blocage des appels commence en fait par un spin-attendant gourmand en processeur avant le blocage. Dans des situations de charge élevée, cela peut faire la différence entre la machine en difficulté ou en panne et le recyclage
Panagiotis Kanavos
@PanagiotisKanavos Je sais, est-ce que ce n'était pas clair d'après ce que j'ai dit?
Yuval Itzchakov
1
Votre réponse ne mentionne pas les spécificités d'IIS - le scénario de fusion / recyclage est une raison principale d'utiliser async tout au long. Quelqu'un qui ne l'a pas vécu ne comprendra probablement pas que cela scale out wellpuisse signifier your server won't die under load. Ou cela peut être un cas deonce burned ...
Panagiotis Kanavos
7

Mes 5 cents:

  1. À utiliser async/awaitsi et seulement si vous effectuez une opération d'E / S, comme une base de données ou un service Web de service externe.
  2. Préférez toujours les appels asynchrones à DB.
  3. Chaque fois que vous interrogez la base de données.

PS Il existe des cas exceptionnels pour le point 1, mais vous devez avoir une bonne compréhension des internes asynchrones pour cela.

Comme avantage supplémentaire, vous pouvez effectuer quelques appels IO en parallèle si nécessaire:

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result
bohdan_trotsenko
la source
6

asyncles actions sont plus utiles lorsque les actions effectuent des opérations d'E / S vers la base de données ou certains appels liés au réseau où le thread qui traite la demande sera bloqué avant qu'il ne reçoive la réponse de la base de données ou de l'appel lié au réseau que vous venez d'appeler. Il est préférable que vous les utilisiez avec eux et cela améliorera vraiment la réactivité de votre application (car moins de threads d'entrée / sortie ASP seront bloqués en attendant la base de données ou toute autre opération comme celle-ci). Dans toutes mes applications, chaque fois que de nombreux appels à la base de données sont très nécessaires, je les ai toujours enveloppés dans une méthode accessible et j'ai appelé cela avec un awaitmot clé.

Dimitri
la source
5

Comme vous le savez, MVC prend en charge les contrôleurs asynchrones et vous devriez en profiter. Dans le cas où votre contrôleur effectue une opération longue (il peut s'agir d'une E / S sur disque ou d'un appel réseau vers un autre service distant), si la demande est traitée de manière synchrone, le thread IIS est occupé tout le temps. Par conséquent, le thread attend simplement la fin de la longue opération. Il peut être mieux utilisé en servant d'autres demandes pendant que l'opération demandée en premier est en cours. Cela vous aidera à traiter plus de demandes simultanées. Votre service Web sera hautement évolutif et ne rencontrera pas facilement le problème C10k . C'est une bonne idée d'utiliser async / wait pour les requêtes db. et oui, vous pouvez les utiliser autant de fois que vous le jugez utile.

Jetez un œil ici pour d'excellents conseils.

anurag
la source
3

D'après mon expérience, de nombreux développeurs utilisent aujourd'hui async/awaitpar défaut les contrôleurs.

Ma suggestion serait de l' utiliser uniquement lorsque vous savez que cela vous aidera .

La raison en est que, comme Stephen Cleary et d'autres l'ont déjà mentionné, cela peut introduire des problèmes de performances plutôt que de les résoudre, et cela ne vous aidera que dans un scénario spécifique:

  • Contrôleurs à fort trafic
  • Backend évolutif
gajama
la source
2

Est-il bon d'utiliser l'action asynchrone partout dans ASP.NET MVC?

Il est bon de le faire partout où vous pouvez utiliser une méthode asynchrone, en particulier lorsque vous rencontrez des problèmes de performances au niveau du processus de travail, ce qui se produit pour des données massives et des opérations de calcul. Sinon, pas besoin car les tests unitaires devront être lancés.

Concernant les méthodes attendues: dois-je utiliser des mots clés asynchrones / attendre quand je veux interroger une base de données (via EF / NHibernate / autre ORM)?

Oui, il est préférable d'utiliser async pour toute opération de base de données autant que possible pour éviter les problèmes de performances au niveau des processus de travail. Notez qu'EF a créé de nombreuses alternatives asynchrones pour la plupart des opérations, telles que:

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

Combien de fois puis-je utiliser des mots clés en attente pour interroger la base de données de manière asynchrone dans une seule méthode d'action?

Le ciel est la limite

Shadi Namrouti
la source
La logique métier de la plupart des applications Web nécessite généralement des opérations hautement séquentielles.Par conséquent, dans la plupart des cas, le basculement entre processus parallèles n'est viable qu'au niveau le plus élevé de la gestion des processus de demande / travailleur Web, qui ne traite pas les demandes de base de données de toute façon directement. Je voudrais vraiment voir des exemples concrets d'une application Web typique où ce serait en fait une bonne idée de traiter les requêtes DB de manière asynchrone.
JustAMartin