Devez-vous mettre à la Tâche.Exécuter dans une méthode pour le rendre asynchrone?
J'essaie de comprendre async vous attendent dans la forme la plus simple. Je veux créer une méthode très simple qui ajoute deux nombres pour les besoins de cet exemple, accordé, il n'est pas temps de traitement à tous, c'est juste une question de formulation d'un exemple ici.
Exemple 1
private async Task DoWork1Async()
{
int result = 1 + 2;
}
Exemple 2
private async Task DoWork2Async()
{
Task.Run( () =>
{
int result = 1 + 2;
});
}
Si j'attends DoWork1Async()
le code est exécuté de manière synchrone ou asynchrone?
Ai-je besoin d'envelopper le code de synchronisation avec Task.Run
pour rendre la méthode awaitable ET asynchrone afin de ne pas bloquer le thread d'INTERFACE utilisateur?
Je suis en train de voir si ma méthode est un Task
ou retourne Task<T>
dois-je placer le code avec Task.Run
pour le rendre asynchrone.
Question stupide, mais je suis sûr que je voir des exemples sur le net où les gens sont en attente de code qui n'a rien asynchrone à l'intérieur et n'est pas enroulé dans un Task.Run
ou StartNew
.
- N'est pas votre premier extrait de vous donner tous les avertissements?
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, nous allons clarifier la terminologie: "asynchrone" (
async
) signifie qu'il peut céder le contrôle de retour pour le thread appelant avant qu'il ne commence. Dans unasync
méthode, ces "rendement" points sontawait
expressions.C'est très différent que le terme "asynchrone", comme (sig)utilisé par la documentation MSDN pour les années à dire "s'exécute sur un thread d'arrière-plan".
Pour de plus amples confondre la question,
async
est très différent de "awaitable"; il y a quelquesasync
des méthodes dont le type de retour ne sont pas awaitable, et de nombreuses méthodes de retour awaitable types qui ne sont pasasync
.Assez sur ce qu'ils ne sont pas; voici ce qu'ils sont:
async
mot-clé permet une méthode asynchrone (qui est, il permetawait
expressions).async
méthodes peuvent retournerTask
,Task<T>
, ou (si vous devez)void
.Task
etTask<T>
.Donc, si nous reformuler votre question "comment puis-je exécuter une opération sur un thread d'arrière-plan d'une manière qui il est awaitable", la réponse est d'utiliser
Task.Run
:(Mais ce modèle est une mauvaise approche, voir ci-dessous).
Mais si votre question est "comment puis-je créer un
async
méthode qui peut le rendement jusqu'à son appelant au lieu de le bloquer", la réponse est de déclarer la méthodeasync
et l'utilisationawait
pour son "rendement" des points:Ainsi, le motif de base des choses, c'est d'avoir
async
code dépendent de "awaitables" dans sonawait
expressions. Ces "awaitables" peut-être d'autresasync
méthodes ou tout simplement des méthodes régulières de retour awaitables. Des méthodes régulières de retourTask
/Task<T>
peut utilisationTask.Run
d'exécuter du code sur un thread d'arrière-plan, ou (plus souvent) qu'ils peuvent utiliserTaskCompletionSource<T>
ou l'un de ses raccourcis (TaskFactory.FromAsync
,Task.FromResult
, etc). Je ne pas recommander l'enchaînement d'un ensemble de méthode dansTask.Run
; les méthodes synchrones doivent avoir synchrone signatures, et il devrait être laissé au consommateur qu'il doit être enveloppé dans unTask.Run
:J'ai un
async
/attendre
intro sur mon blog; à la fin, il est intéressant de suivi des ressources. La MSDN docs pourasync
sont exceptionnellement bonnes, trop.async
méthodes doivent retournerTask
,Task<T>
, ouvoid
.Task
etTask<T>
sont awaitable;void
ne l'est pas.async void
signature de la méthode de compiler, c'est juste une très mauvaise idée que vous perdez votre pointeur de votre tâche asynchronevoid
n'est pas awaitable.var result = Task.Run(() => AwaitableTaskIMustUse()).Result;
?Task.Run(() => SomethingAsync()).GetAwaiter().GetResult()
seulement siSomethingAsync
peut en toute sécurité être exécuté sur un thread du pool et de votre application n'est pas en danger de pool de threads de la famine.Task.Run
(commeDoWorkAsync
dans cette réponse). À l'aide deTask.Run
à appel une méthode à partir d'une INTERFACE utilisateur contexte est approprié (commeDoVariousThingsFromTheUIThreadAsync
).HttpClient
).Task.Run
.var t = await Task.Run(() => MyOldLibrarySynchronousMethod()); // is this blocking a thread pool thread, even though it yields to the calling thread?
Task.Run
va bloquer un thread du pool. C'est bien d'appeler les vieux modes de synchronisation avecawait Task.Run
, mais vous ne voulez pas exposer un async-à la recherche wrapper - c'est ce que j'appelle des "faux async". Vous voudrez peut-être vérifier monTask.Run
l'étiquette de la série.await Task.Run
pour appeler une méthode de synchronisation, il est clair qu'il va faire, c'est à dire exécuter une méthode de synchronisation sur un thread d'arrière-plan et de bloquer l'ensemble du thread?Task.Run
à appeler d'une méthode, mais si il y a unTask.Run
autour de tous (ou presque tous) le code de la méthode, puis que c'est un anti-pattern - il suffit de garder la méthode synchrone et déplacer leTask.Run
jusqu'à un niveau.L'une des choses les plus importantes à retenir lors de la décoration d'une méthode avec async est qu'au moins il n'y a un attendent opérateur à l'intérieur de la méthode. Dans votre exemple, je voudrais le traduire comme indiqué ci-dessous à l'aide de TaskCompletionSource.
Lorsque vous utilisez la Tâche.Exécuter pour exécuter une méthode, la Tâche devient un thread du pool de threads pour exécuter cette méthode. Donc, à partir de la thread de l'INTERFACE utilisateur, il est "asynchrone", comme on ne veut pas bloquer le thread d'INTERFACE utilisateur.C'est bien pour l'application de bureau que vous n'avez généralement pas besoin de beaucoup de fils pour prendre soin d'interactions de l'utilisateur.
Toutefois, pour l'application de web chaque demande est traitée par un thread du pool de thread et donc le nombre de demandes actives peut être augmenté par l'économie de tels fils. Souvent en utilisant des threads de pool de threads pour simuler l'opération asynchrone n'est pas extensible pour les applications web.
Vrai Asynchrone n'est pas nécessairement impliquant l'utilisation d'un thread pour les opérations d'e/S, tels que le fichier /DB accès, etc. Vous pouvez lire ceci pour comprendre pourquoi l'opération d'e/S n'a pas besoin de fils. http://blog.stephencleary.com/2013/11/there-is-no-thread.html
Dans votre exemple simple,c'est un pur lié au PROCESSEUR de calcul, donc à l'aide de la Tâche.Run est fine.