web-dev-qa-db-fra.com

Quand devrais-je utiliser les contrôleurs Async dans ASP.NET MVC?

J'ai quelques problèmes à utiliser des actions asynchrones dans ASP.NET MVC. Quand améliore-t-il les performances de mes applications et quand 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 async/wait lorsque je souhaite interroger une base de données (via EF/NHibernate/other ORM)?
  3. Combien de fois puis-je utiliser des mots-clés wait pour interroger la base de données de manière asynchrone dans la méthode ne action unique?
197
Vnuuk

Les méthodes d'action asynchrone sont utiles lorsqu'une action doit exécuter plusieurs opérations à exécution longue indépendantes.

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

Les appels à la 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 constitue 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, le fait de répartir plus de travail sur un serveur de base de données surchargé en utilisant des appels asynchrones ne fait que déplacer davantage la charge sur 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 de @PanagiotisKanavos:

De plus, async ne veut pas dire parallèle. L'exécution asynchrone libère un thread threadpool précieux du blocage d'une ressource externe, sans complexité ni coût en performances. Cela signifie que la même machine IIS peut gérer davantage de demandes simultanées, mais pas plus rapidement.

Vous devez également considérer que les appels bloquants commencent par un spinwait gourmand en ressources processeur. En période de tension, le blocage des appels entraînera une augmentation des délais et le recyclage du pool d'applications. Les appels asynchrones évitent tout simplement cela

98
Tharif

Vous pouvez trouver utile mon article MSDN sur le sujet utile ; J'ai pris beaucoup de place dans cet article en décrivant quand vous devriez utiliser async sur ASP.NET, pas seulement comment pour utiliser async sur ASP.NET.

J'ai quelques problèmes à utiliser des actions asynchrones dans ASP.NET MVC. Quand cela améliore les performances de mes applications et quand - pas.

Tout d’abord, comprenez que async/await consiste à 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 requête afin que le serveur puisse évoluer.

En particulier, il ne sera pas:

  • Faites vos demandes individuelles complètes plus rapidement. En fait, ils termineront (un peu plus tôt) plus lentement.
  • Revenez à l'appelant/au navigateur lorsque vous frappez un await. await uniquement "renvoie" au pool de threads ASP.NET, pas au navigateur.

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

Je dirais que c'est bien de l'utiliser partout où vous faites I/O. Cela ne sera pas forcément 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 de async en appelant simplement Task.Run dans leurs contrôleurs. C'est une idée horrible. Parce que ce code finit par libérer le thread de requête en prenant un autre thread, il n'y a donc aucun avantage (et en fait, ils encourent la pénalisation de commutateurs de threads supplémentaires)!

Dois-je utiliser des mots-clés async/wait lorsque je souhaite interroger une base de données (via EF/NHibernate/other ORM)?

Vous pouvez utiliser toutes les méthodes disponibles et disponibles. À l'heure actuelle, la plupart des principaux acteurs prennent en charge async, mais quelques-uns ne le font pas. Si votre ORM ne prend pas en charge async, n'essayez pas de l'envelopper dans Task.Run ou quelque chose du genre (voir ci-dessus).

Notez que j'ai dit "vous pourriez utiliser". Si vous parlez d'ASP.NET MVC avec un seul backend de base de données, vous ne profiterez (presque certainement) d'aucun avantage d'évolutivité de async. En effet, IIS peut gérer beaucoup plus de demandes simultanées qu'une seule instance de serveur SQL (ou autre SGBDR classique). Toutefois, si votre système est plus moderne - un cluster de serveurs SQL, Azure SQL, NoSQL, etc. - et que votre système peut être mis à l’échelle, et que votre goulot d’extensibilité est IIS, , vous pouvez obtenir . un avantage d'évolutivité de 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 avec une seule méthode d'action?

Autant que tu veux. Toutefois, 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.

Aussi, gardez à 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 conserver SQLServer à pleine capacité, doubler ou tripler la pression exercée sur SQLServer ne vous aidera pas du tout.

214
Stephen Cleary

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

Comme d'habitude en programmation, cela dépend de . Il y a toujours un compromis à faire pour emprunter un certain chemin.

async-await brille aux endroits où vous savez que vous recevrez des demandes simultanées auprès de votre service et que vous voulez pouvoir bien évoluer . Comment async-await aide-t-il à l’extension? Dans le fait que lorsque vous appelez un IO asynchrone de manière synchrone , par exemple un appel réseau ou une frappe sur votre base de données, le thread actuel qui est responsable de l'exécution est bloqué en attente de la fin de la demande. Lorsque vous utilisez async-await, vous activez la structure pour créer une machine à états qui garantit que, une fois l'appel IO terminé, votre méthode continue de s'exécuter à l'endroit où elle s'est arrêtée.

Une chose à noter est que cette machine d'état a une surcharge subtile. Rendre une méthode asynchrone ne lui permet pas d’exécuter plus rapidement , ce qui est un facteur important à comprendre et une idée fausse que beaucoup de personnes ont.

Une autre chose à prendre en compte lors de l’utilisation de async-await est le fait qu’elle est asynchrone tout le chemin , ce qui signifie que vous verrez l’async pénétrer dans votre pile d’appel, en haut. à bout. Cela signifie que si vous voulez exposer des API synchrones, vous vous retrouverez souvent en train de dupliquer une certaine quantité de code, car async et sync ne se mélangent pas très bien.

Dois-je utiliser des mots-clés async/wait lorsque je souhaite interroger une base de données (via EF/NHibernate/other ORM)?

Si vous choisissez d'utiliser des appels asynchrones IO, alors oui, async-await sera un bon choix, car de plus en plus de fournisseurs de bases de données modernes exposent une méthode asynchrone implémentant le TAP (Task Asynchronous Modèle).

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

Autant que vous voulez, 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 vos requêtes sont indépendantes les unes des autres et peuvent être effectuées simultanément, vous pouvez créer une nouvelle tâche pour chacune d'entre elles et utiliser await Task.WhenAll pour attendre que les deux soient terminées.

19
Yuval Itzchakov

Mes 5 centimes:

  1. Utilisez async/await si et seulement si vous effectuez une opération IO, comme une base de données ou un service Web de service externe.
  2. Toujours préférer les appels asynchrones à la base de données.
  3. Chaque fois que vous interrogez la base de données.

P.S. Il existe des cas exceptionnels pour le point 1, mais pour cela, vous devez bien comprendre les éléments internes asynchrones.

Un avantage supplémentaire est que vous pouvez faire quelques IO appels 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
7
bohdan_trotsenko

async les actions sont plus utiles lorsque les actions exécutent certaines opérations I\O sur la base de données ou des appels liés au réseau, où le thread qui traite la demande sera bloqué avant d’obtenir une réponse de la base ou de l’appel lié au réseau que vous venez d’appeler. Il est préférable d’attendre avec eux et cela améliorera réellement la réactivité de votre application (car moins de threads d’entrée/de sortie ASP seront bloqués lors de l’attente de la base de données ou de toute autre opération similaire). Dans toutes mes applications chaque fois que de nombreux appels à la base de données sont très nécessaires, je les ai toujours emballés dans une méthode paramétrable et appelé cela avec le mot clé await.

6
Dimitri

Comme vous le savez, MVC prend en charge les contrôleurs asynchrones et vous devez en tirer parti. Si votre contrôleur effectue une longue opération (par exemple une entrée/sortie sur disque ou un appel réseau à un autre service distant), si la demande est traitée de manière synchrone, le thread IIS est occupé. tout le temps. En conséquence, le thread attend juste que l'opération longue se termine. Il peut être mieux utilisé en répondant à d'autres demandes pendant que l'opération demandée en premier est en cours. Cela aidera à répondre à 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 de base de données. Et oui, vous pouvez les utiliser autant de fois que vous le souhaitez.

Jetez un coup d'oeil ici pour un excellent conseil.

4
anurag

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

Il est bon de le faire chaque fois que 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 opérations volumineuses de données et de calcul. Sinon, inutile car les tests unitaires nécessiteront un casting.

Concernant les méthodes attendues: dois-je utiliser des mots-clés async/wait lorsque je souhaite interroger une base de données (via EF/NHibernate/other ORM)?

Oui, il est préférable d’utiliser async pour toutes les opérations de base de données afin d’éviter les problèmes de performances au niveau des processus de travail. Notez que 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 wait pour interroger la base de données de manière asynchrone avec une seule méthode d'action?

Le ciel est la limite

2
Shadi Namrouti

Mon expérience est qu’aujourd’hui, de nombreux développeurs utilisent async/await par défaut pour les contrôleurs.

Ma suggestion serait, de l'utiliser seulement quand vous savez que cela vous aidera .

La raison en est, comme Stephen Cleary et d'autres déjà mentionnés, cela peut poser 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
1
gajama