J'ai une async
méthode qui ne renvoie aucune donnée:
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
J'appelle cela à partir d'une autre méthode qui renvoie des données:
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
Appeler MyAsyncMethod()
sans l'attendre provoque un avertissement « Parce que cet appel n'est pas attendu, la méthode actuelle continue de s'exécuter avant la fin de l'appel » dans Visual Studio. Sur la page de cet avertissement, il est indiqué:
Vous ne devez envisager de supprimer l'avertissement que si vous êtes sûr de ne pas attendre la fin de l'appel asynchrone et que la méthode appelée ne déclenche aucune exception .
Je suis sûr que je ne veux pas attendre la fin de l'appel; Je n'en ai pas besoin ni le temps. Mais l'appel pourrait soulever des exceptions.
Je suis tombé sur ce problème à plusieurs reprises et je suis sûr que c'est un problème commun qui doit avoir une solution commune.
Comment appeler en toute sécurité une méthode asynchrone sans attendre le résultat?
Mettre à jour:
Pour les personnes suggérant que j'attends juste le résultat, il s'agit d'un code qui répond à une requête Web sur notre service Web (API Web ASP.NET). L'attente dans un contexte d'interface utilisateur laisse le thread d'interface utilisateur libre, mais l'attente dans un appel de demande Web attendra que la tâche se termine avant de répondre à la demande, augmentant ainsi les temps de réponse sans raison.
la source
MyAsyncMethod().Wait()
Réponses:
Si vous voulez obtenir l'exception "asynchrone", vous pouvez faire:
Cela vous permettra de traiter une exception sur un thread autre que le thread "principal". Cela signifie que vous n'avez pas à "attendre" l'appel
MyAsyncMethod()
depuis le thread qui appelleMyAsyncMethod
; mais, vous permet toujours de faire quelque chose avec une exception - mais seulement si une exception se produit.Mettre à jour:
techniquement, vous pourriez faire quelque chose de similaire avec
await
:... ce qui serait utile si vous aviez besoin d'utiliser spécifiquement
try
/catch
(ouusing
) mais je trouve queContinueWith
c'est un peu plus explicite parce que vous devez savoir ce que celaConfigureAwait(false)
signifie.la source
Task
: classe statique publique AsyncUtility {public static void PerformAsyncTaskWithoutAwait (cette tâche, Action <Task> exceptionHandler) {var dummy = task.ContinueWith (t => exceptionHandler (t), TaskContinuationOptions.OnlyOnFaulted); }} Utilisation: MyAsyncMethod (). PerformAsyncTaskWithoutAwait (t => log.ErrorFormat ("Une erreur s'est produite lors de l'appel de MyAsyncMethod: \ n {0}", t.Exception));ConfiguratAwait(false)
ne s'exécute pas tant que la tâche n'est pas terminée, mais le thread actuel n'attend pas (c'est-à-dire le bloc) pour cela, la ligne suivante est appelée de manière asynchrone à l'appel en attente. SansConfigureAwait(false)
cela, la ligne suivante serait exécutée dans le contexte de la demande Web d'origine. AvecConfigurateAwait(false)
elle, elle est exécutée dans le même contexte que la méthode async (tâche), libérant le contexte / thread d'origine pour continuer ...Vous devez d'abord envisager de créer
GetStringData
uneasync
méthode et de lui faireawait
renvoyer la tâcheMyAsyncMethod
.Si vous êtes absolument sûr que vous n'avez pas besoin de gérer les exceptions
MyAsyncMethod
ou de savoir quand cela se termine, vous pouvez le faire:BTW, ce n'est pas un "problème commun". Il est très rare de vouloir exécuter du code sans se soucier s'il se termine et sans se soucier s'il se termine avec succès.
Mettre à jour:
Puisque vous êtes sur ASP.NET et que vous souhaitez revenir tôt, vous pouvez trouver mon article de blog sur le sujet utile . Cependant, ASP.NET n'a pas été conçu pour cela et il n'y a aucune garantie que votre code s'exécutera après le retour de la réponse. ASP.NET fera de son mieux pour le laisser fonctionner, mais il ne peut pas le garantir.
Donc, c'est une bonne solution pour quelque chose de simple comme jeter un événement dans un journal où cela n'a pas vraiment d' importance si vous en perdez quelques-uns ici et là. Ce n'est pas une bonne solution pour tout type d'opérations critiques pour l'entreprise. Dans ces situations, vous devez adopter une architecture plus complexe, avec un moyen persistant pour enregistrer les opérations (par exemple, Azure Queues, MSMQ) et un processus d'arrière-plan distinct (par exemple, Azure Worker Role, Win32 Service) pour les traiter.
la source
var _ = MyAsyncMethod();
par_ = MyAsyncMethod();
. Cela évite toujours l'avertissement CS4014, mais cela rend un peu plus explicite que vous n'utilisez pas la variable.La réponse de Peter Ritchie était ce que je voulais, et l'article de Stephen Cleary sur le retour précoce dans ASP.NET a été très utile.
Cependant, en tant que problème plus général (non spécifique à un contexte ASP.NET), l'application console suivante montre l'utilisation et le comportement de la réponse de Peter en utilisant
Task.ContinueWith(...)
GetStringData()
retourne tôt sans attendreMyAsyncMethod()
et les exceptions levéesMyAsyncMethod()
sont traitées dansOnMyAsyncMethodFailed(Task task)
et non dans letry
/catch
aroundGetStringData()
la source
Console.ReadLine();
et ajoutez un peu de sommeil / retardMyAsyncMethod
et vous ne verrez jamais l'exception.Je me retrouve avec cette solution:
la source
C'est ce qu'on appelle le feu et oublier, et il y a une extension pour cela.
Installez le paquet nuget .
Utilisation:
la source
Je suppose que la question se pose, pourquoi auriez-vous besoin de faire cela? La raison de
async
C # 5.0 est que vous pouvez attendre un résultat. Cette méthode n'est pas réellement asynchrone, mais simplement appelée à la fois afin de ne pas trop interférer avec le thread courant.Il serait peut-être préférable de démarrer un thread et de le laisser se terminer seul.
la source
async
est un peu plus que simplement "attendre" un résultat. "attendre" implique que les lignes qui suivent "attendent" sont exécutées de manière asynchrone sur le même thread qui a appelé "attendre". Cela peut être fait sans "attendre", bien sûr, mais vous finissez par avoir un tas de délégués et vous perdez l'apparence séquentielle du code (ainsi que la possibilité d'utiliserusing
ettry/catch
...await
mot - clé et n'utilise pas leasync
mot - clé, mais il n'y a aucun intérêt à utiliser leasync
mot - clé sans utiliser égalementawait
dans la définition de cette méthode.async
est un peu plus que" l'attente "d'un résultat." Leasync
mot-clé (vous avez laissé entendre que c'est le mot-clé en le mettant entre guillemets) ne signifie rien de plus qu'attendre le résultat. C'est l'asynchronie, comme les concepts CS généraux, cela signifie plus que simplement attendre un résultat.async
crée une machine d'état qui gère toutes les attentes dans la méthode async. S'il n'y a pas deawait
s dans la méthode, elle crée toujours cette machine d'état - mais la méthode n'est pas asynchrone. Et si laasync
méthode revientvoid
, il n'y a rien à attendre. Donc, c'est plus qu'attendre un résultat.async
mot - clé. Tout ce que vous devez faire (et tout ce qui se passe finalement avec une machine à états dans ce cas particulier) est que la méthode est exécutée de manière synchrone puis encapsulée dans une tâche terminée. Je suppose que techniquement, vous ne supprimez pas simplement la machine d'état; vous supprimez la machine d'état, puis appelezTask.FromResult
. Je supposais que vous (et aussi les rédacteurs du compilateur) pourriez ajouter l'addendum par vous-même.Sur les technologies avec des boucles de messages (vous ne savez pas si ASP en fait partie), vous pouvez bloquer la boucle et traiter les messages jusqu'à la fin de la tâche et utiliser ContinueWith pour débloquer le code:
Cette approche est similaire au blocage sur ShowDialog et à la réactivité de l'interface utilisateur.
la source
Je suis en retard à la fête ici, mais il y a une bibliothèque géniale que j'utilise et que je n'ai pas vue référencée dans les autres réponses
https://github.com/brminnick/AsyncAwaitBestPractices
Si vous devez "Fire And Forget" vous appelez la méthode d'extension sur la tâche.
Passer l'action onException à l'appel garantit que vous obtenez le meilleur des deux mondes - pas besoin d'attendre l'exécution et de ralentir vos utilisateurs, tout en conservant la possibilité de gérer l'exception de manière gracieuse.
Dans votre exemple, vous l'utiliseriez comme ceci:
Il fournit également des AsyncCommands attendus implémentant ICommand, ce qui est idéal pour ma solution MVVM Xamarin
la source
La solution consiste à démarrer le HttpClient dans une autre tâche d'exécution sans contexte de sincronisation:
la source
Si vous voulez vraiment faire ça. Juste pour adresser "Appeler une méthode asynchrone en C # sans attendre", vous pouvez exécuter la méthode asynchrone à l'intérieur d'un
Task.Run
. Cette approche attendra laMyAsyncMethod
fin.await
déballe de manière asynchrone laResult
tâche, tandis que l'utilisation de Résultat bloquerait jusqu'à ce que la tâche soit terminée.la source
La méthode asynchrone renvoie généralement la classe Task. Si vous utilisez une
Wait()
méthode ou uneResult
propriété et que le code lève une exception - le type d'exception est enveloppé dansAggregateException
- vous devez alors interrogerException.InnerException
pour localiser l'exception correcte.Mais il est également possible d'utiliser à la
.GetAwaiter().GetResult()
place - il attendra également la tâche asynchrone, mais ne terminera pas l'exception.Voici donc un petit exemple:
Vous voudrez peut-être également être en mesure de renvoyer certains paramètres de la fonction asynchrone - cela peut être réalisé en fournissant un supplément
Action<return type>
dans la fonction asynchrone, par exemple comme ceci:Veuillez noter que les méthodes asynchrones ont généralement un
ASync
nom de suffixe, juste pour éviter la collision entre les fonctions de synchronisation avec le même nom. (Par exempleFileStream.ReadAsync
) - J'ai mis à jour les noms de fonctions pour suivre cette recommandation.la source