Imaginez la situation suivante. Il existe une interface utilisateur et l'opération de longue durée doit être appelée sans bloquer le thread principal. l'opération de longue durée appelle elle-même d'autres méthodes, qui n'interagissent pas avec le thread de l'interface utilisateur.
Dans la plupart des cas, les méthodes appelées à partir des méthodes B et C ont des alternatives synchrones à leurs homologues Async. La question est: peuvent-ils être utilisés en toute sécurité au lieu de leur homologue asynchrone? Disons DbContext.DbSet.Add au lieu de AddAsync
// UI public async Task UiMethodAsync() { var result = await MethodAAsync(); } // some component public Task<bool> MethodAAsync() { return Task.FromResult(MethodB()); } public bool MethodB() { return MethodC(); } public bool MethodC() { return DbContext.Set<TEntit>.Any(); }
Ma question est la suivante: est-il nécessaire de rendre toutes les méthodes asynchrones pour empêcher le thread de l'interface utilisateur de se bloquer ou serait-ce bien eben assez pour rendre les méthodes B et C de manière synchrone comme ceci:
// UI public async Task UiMethodAsync() { var result = await MethodAAsync(); } // some component public async Task<bool> MethodAAsync() { return await MethodBAsync().ConfigureAwait(false); } public async Task<bool> MethodBAsync() { return await MethodCAsync().ConfigureAwait(false); } public async Task<bool> MethodCAsync() { return await DbContext.Set<TEntit>.AnyAsync().ConfigureAwait(false); }
bien sûr cela dépend de ce que font MethodB et C, s'ils interagissent avec le thread de l'interface utilisateur ou non. mais disons qu'ils ne le font pas et doivent simplement calculer les choses et renvoyer un résultat.
Est-il nécessaire de les rendre asynchrones également? Je suppose que non. Je pense que cela évite probablement des frais généraux inutiles pour la gestion des tâches et des threads.
3 Réponses :
Il ne suffit pas d'ajouter le mot clé async pour que votre code ne se bloque pas.
Une fonction renvoyant une tâche se bloquera toujours à moins que les appels ne soient complètement asynchrones.
C'est difficile à expliquer, mais pour mettre en évidence une partie de votre code:
public async Task<bool> MethodA() { bool b = MethodB(); return Task.FromResult(b); }
Est équivalent à
public async Task<bool> MethodA() { return Task.FromResult(MethodB()); }
Il est clair maintenant que la première ligne de code est bloquante, et la tâche n'est créée qu'à la deuxième ligne.
p >
Il était clair auparavant que l'appel à MethodB bloquera le thread en cours d'exécution. MAIS ce qui n'est pas clair: L'interface utilisateur / thread principal sera-t-il bloqué si MethodAAsync est appelé avec async wait? UI / Main-Thread n'est alors pas le même que le thread qui exécute les méthodes B et C
Oui, il sera bloqué. Un B & C sera tous sur le même thread d'interface utilisateur. L'utilisation de mots-clés async / await ne suffit pas pour créer un nouveau thread.
Pourquoi sera-t-il bloqué?
Pourquoi pensez-vous que ce serait sur un autre fil? Vous ne passez à un autre thread que via quelque chose comme Task.Run ()
ou DbContext.Set.AnyAsync ()
avec cette logique, pourquoi AnyAsync devrait-il mettre quelque chose sur un thread différent? Appelle-t-il Task.Run ()?
Oui ou du moins il doit appeler quelque chose de similaire.
Ce code se compile-t-il? Le mot clé async ne devrait-il pas être supprimé?
@PauloMorgado Je n'essaye pas de compiler des questions SO. C'est un peu hors sujet pour moi.
@Paulo asynchrone sans attendre la compilation. mais vous obtenez l'avertissement que le code sera exécuté de manière synchrone. async permet uniquement d'utiliser le mot clé wait. de toute façon je l'ai supprimé de l'exemple de code.
@Buh Buh. Si Async / await ne suffit pas pour exécuter quelque chose sur un thread différent, alors je n'ai absolument pas l'avantage d'utiliser async / await. Son utilisation principale est d'exécuter quelque chose sur un thread différent pour ne pas bloquer le thread principal / UI. Cela semble très peu logique.
Prenons ceci pour discuter: chat.stackoverflow.com/rooms/210386/…
Une méthode qui renvoie une Task
crée une attente qui ne bloquera pas le thread appelant. Du moins pas pendant une longue période. Mais cela n'est pas imposé par la machinerie d'attente asynchrone. Il est possible, et en fait très facile, d'écrire une méthode qui brise cette attente. Par exemple:
public Task DoStuffTheWrongWayAsync() { Thread.Sleep(1000); // Simulate a heavy computation, or a blocking call return Task.CompletedTask; }
Tout thread qui appelle cette méthode sera bloqué pendant une seconde, puis recevra une tâche terminée. Je ne sais pas si cet anti-modèle a un nom établi. Fake-asynchrony vient à l'esprit, bien que cela puisse également être utilisé pour le cas où l'appelant n'est pas bloqué, mais qu'un autre thread pauvre est bloqué à la place. L'essentiel est qu'une méthode asynchrone bien comportée devrait renvoyer immédiatement une Tâche
, laissant le thread appelant libre de faire d'autres tâches (comme répondre aux événements de l'interface utilisateur s'il s'agit d'un thread d'interface utilisateur).
De manière générale, si vous voulez rendre quelque chose asynchrone, vous commencez au niveau le plus bas - les API qui font réellement le travail d'E / S. Dans votre exemple, AnyAsync
serait la première chose rendue asynchrone. Ensuite, laissez l'asynchronie se développer à partir de là (jusqu'à MethodC
, puis MethodB
, puis MethodA
et enfin UiMethod
).
Il est normal de se retrouver avec une asynchrone en cours " tout le chemin ".
Est-il nécessaire de les rendre asynchrones également? Je suppose que non.
Oui. Si vous voulez qu'ils soient asynchrones, ils doivent être asynchrones. Task.FromResult
est pour les implémentations synchrones; ils ne seront pas asynchrones.
Imaginez la situation suivante. Il existe une interface utilisateur ... les méthodes appelées à partir des méthodes B et C ont des alternatives synchrones à leurs homologues Async. La question est: peuvent-ils être utilisés en toute sécurité au lieu de leur homologue asynchrone?
Une chose que vous pouvez faire dans le monde de l'interface utilisateur est en enveloppant les appels à des méthodes synchrones dans Task.Run
. Par exemple:
public async Task UiMethodAsync() { var result = await Task.Run(MethodA); }
Ceci est une technique utile pour les situations où vous avez une application côté client, ne voulez pas bloquer l'interface utilisateur, mais ne voulez pas non plus prendre le temps de convertir tout le code en étant asynchrone. Notez que ce n'est pas approprié pour les applications côté serveur telles que ASP.NET.
J'ai choisi Task.Run pour résoudre le problème de ne pas bloquer l'interface utilisateur. Une question demeure: si async / await ne lance pas quelque chose sur un thread différent. quel est l'avantage de l'utiliser alors? Seulement pour que le parallélisme fasse autre chose entre les deux, avec bloquant également le thread actuel?
async
est une forme de concurrence sans utilisation de threads. Le but est de libérer des threads. Pour les applications clientes, la libération du thread d'interface utilisateur permet la réactivité. Pour les applications serveur, la libération des threads de travail permet une évolutivité.
pourquoi async / await charge-t-il n'importe quel thread s'il ne crée pas de nouveaux threads? s'agit-il de parallélisme sans threads supplémentaires?
si MethodC n'a rien à attendre, alors il n'aurait aucune raison d'être marqué comme asynchrone. etc., etc
Cela dépend à peu près de ce que font les méthodes B et C. S'ils font des E / S, c'est une bonne idée de les rendre asynchrones également. S'ils ne font que des travaux gourmands en ressources processeur, vous pouvez également adopter la deuxième approche.
Dans la plupart des cas, les méthodes appelées à partir des méthodes B et C ont une alternative synchrone à l'appel Async utilisé. Le questino est de savoir s'ils peuvent être utilisés en toute sécurité au lieu de leur homologue asynchrone. Disons DbContext.DbSet.Add au lieu de AddAsync
Si MethodC fait quelque chose qui doit attendre, chaque méthode appelante doit être marquée comme asynchrone et chaque appel attendu
@SvenKrauter clairement la version asynchrone d'une méthode fait le même travail que la version sync. Async est une technologie d'exécution différente par le .NET. Veuillez consulter docs
@SvenKrauter: Si vous voulez être sûr de ne pas bloquer le thread principal, vous pouvez exécuter la méthode, synchrone ou asynchrone, sur un thread d'arrière-plan. Le fait qu'une méthode async bloque le thread appelant dépend entièrement de l'implémentation. Il peut ressembler et avoir la signature d'une méthode asynchrone mais se comporter comme une méthode synchrone (bloquante). Vous ne pouvez pas le savoir avec certitude si vous n'en regardez pas la mise en œuvre. Assigner le mot-clé
async
à une méthode ne la rend pas automatiquement asynchrone.En remarque, selon les guidelines les méthodes asynchrones doivent avoir le suffixe
Async
. Ainsi, votre méthodeUiMethod
doit être renommée enUiMethodAsync
etc.Liés: stackoverflow.com/questions/21033150/...
@HansKe st ing cette question n'a pas par rapport à cette question. Cette question concerne deux alternatives pratiquement équivalentes en termes de comportement et d'évolutivité (en choisir une est une question de goût). Cette question concerne deux alternatives qui diffèrent radicalement par leur comportement et leur évolutivité (l'une est clairement préférable à l'autre).
@Theodor Zoulias. Les noms des méthodes n'ont été choisis qu'à des fins de démonstration. de toute façon j'ai mis à jour le code pour éviter les mauvaises pratiques aux autres.