D'accord, cela semble étrange, mais le code est très simple et explique bien la situation.
public virtual async Task RemoveFromRoleAsync(AzureTableUser user, string role)
{
AssertNotDisposed();
var roles = await GetRolesForUser(user);
roles.Roles = RemoveRoles(roles.Roles, role);
await Run(TableOperation.Replace(roles));
}
(Je sais que je parle en quelque sorte dans l'abstrait ci-dessous, mais ce qui précède est une méthode réelle de ce qui sera le code de production réel qui fait réellement ce que je demande ici, et je suis réellement intéressé par votre examen pour l'exactitude par rapport au modèle asynchrone / attente.)
Je rencontre ce modèle de plus en plus souvent maintenant que j'utilise async
/ await
more. Le modèle se compose de la chaîne d'événements suivante:
- Attendez un premier appel qui me fournira des informations sur lesquelles je dois travailler
- Travailler sur ces informations de manière synchrone
- Attendre un dernier appel qui enregistre le travail mis à jour
Le bloc de code ci-dessus est généralement la façon dont je gère ces méthodes. Je await
le premier appel, que je dois parce qu'il est asynchrone. Ensuite, je fais le travail que je dois faire, qui n'est pas lié aux E / S ou aux ressources, et qui n'est donc pas asynchrone. Enfin, j'enregistre mon travail qui est aussi un async
appel, et hors du cargo-culte je await
le fais .
Mais est-ce la façon la plus efficace / correcte de gérer ce modèle? Il me semble que je pourrais sauter await
le dernier appel, mais qu'en est-il en cas d'échec? Et dois-je utiliser une Task
méthode telle que ContinueWith
de chaîner mon travail synchrone avec l'appel d'origine? Je suis juste à un point en ce moment où je ne sais pas si je gère cela correctement.
Compte tenu du code de l'exemple , existe-t-il une meilleure façon de gérer cette chaîne d'appel de méthode async / sync / async?
la source
Réponses:
Oui, je pense que c'est la bonne façon de procéder.
Vous ne pouvez pas sauter la seconde
await
. Si vous le faisiez, la méthode semblerait se terminer trop tôt (avant que la suppression ne soit réellement effectuée) et vous ne sauriez jamais si la suppression a échoué.Je ne vois pas comment cela pourrait
ContinueWith()
aider quoi que ce soit ici. Vous pouvez l'utiliser pour éviter de l'utiliserawait
, mais cela rendrait votre code plus compliqué et moins lisible. Et c'est là tout l'intérêtawait
: simplifier l'écriture de code asynchrone, par rapport à l'utilisation de continuations.la source
La façon de gérer ce modèle consiste à garantir que toutes les E / S sont asynchrones. Les méthodes d'E / S synchrones provoquent le blocage du thread actuel pendant qu'il attend une réponse de la destination d'E / S (réseau, système de fichiers, etc.).
Une autre chose à considérer est celle qui
await
doit être utilisée lorsque vous avez besoin d'une valeur de retour ou lorsque vous avez besoin du code attendu pour terminer avant de faire autre chose. Si vous n'avez besoin d'aucune de ces choses, vous pouvez "tirer et oublier" votre méthode asynchrone avecTask.Run
.Ainsi, pour l'utilisation la plus efficace des ressources informatiques, s'il y a
RemoveRoles
des E / S, elles doivent devenirawait RemoveRolesAsync
et les méthodes d'E / S appelées parRemoveRolesAsync
doivent également être asynchrones (et éventuellement attendues).Si les performances ne sont pas votre principale préoccupation, il est possible d'effectuer des E / S synchrones sur un thread asynchrone. C'est une dette technique cependant. (Dans ce cas, vous souhaiterez peut -être appeler la première méthode asynchrone avec
ConfigureAwait
, selon l'emplacement d'exécution du code.)Voici un aperçu plus approfondi des meilleures pratiques - https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Voici quelques notes sur le comportement de ConfigureAwait dans différents environnements comme ASP.NET, WebAPI, etc. - /programming/13489065/best-practice-to-call-configureawait-for-all-server-side -code
la source