Fire and Forget approche
Liées à cette réponse,
Si j'ai vraiment envie de "Fire and Forget", une méthode qui retourne une tâche, et (pour la simplicité) supposons que la méthode n'est pas prévu de lancer une quelconque des exceptions. Je peux utiliser la méthode d'extension énumérées dans la réponse:
public static void Forget(this Task task)
{
}
À l'aide de cette approche, si il y a des bugs dans l'action de la Task
qui provoquent la levée d'une exception alors quand l'inattendu exception est levée, l'exception sera d'ingestion et de passer inaperçu.
Question: ne Serait-il pas plus approprié dans ce scénario, la méthode d'extension pour être de la forme:
public static async void Forget(this Task task)
{
await task;
}
De sorte que les erreurs de programmation lever une exception et obtenir de l'escalade (généralement de ramener le processus).
Dans le cas d'une méthode avec des prévu (et ignorable) exceptions près, la méthode aurait besoin pour devenir plus élaboré (en aparté, des suggestions sur la façon de construire une version de cette méthode qui prendrait une liste acceptable et ignorable les types d'exception?)
Vous devez vous connecter pour publier un commentaire.
Il dépend de la sémantique que vous voulez. Si vous voulez vous assurer que les exceptions sont notées, alors oui, vous pourriez
await
la tâche. Mais dans ce cas il n'est pas vraiment "fire and forget".Un vrai "fire and forget" - dans le sens que vous ne se soucient pas lorsqu'elle est terminée ou si elle se termine avec succès ou avec d'erreur est extrêmement rare.
Edit:
Pour la gestion des exceptions:
Remarque que je vous recommande d'utiliser
await
au lieu deContinueWith
.ContinueWith
a une surprenante par défaut planificateur (comme indiqué sur mon blog) etTask.Exception
clôturera l'exception dans unAggregateException
, rendant le code de gestion d'erreur de plus en plus lourde.async void
à un certain niveau?try
/catch
est ce que vous auriez besoin. Édité pour montrer un exemple de code.Forget
universelle de stub pour fire-and-forget, sanstry/catch
à l'intérieur. Et de laisser le sélectifs de la gestion de l'exception à la tâche passé àForget
. De cette façon, ce qui fait uncaught serait immédiat jeté sur l'actuel contexte de synchronisation. J'aime ça 🙂.ConfigureAwait(false)
en place, toutes les exceptions inattendues toujours être affichés à l'SynchronizationContext
qui a été actif au début de la méthode?catch
bloc ne sera pas exécuté dans la capture du contexte (de sorte que toute la journalisation ou ce ne sera pas), mais si l'exception n'est pas acceptable et est renvoyé (throw;
), alors oui, l'exception sera (re-)posées sur l'SynchronizationContext
qui a été actif au début deForget
.SynchronizationContext.Send
de la capture d'contexte pourasync void
? Tks.Post
, en fait.Oui si vous étiez intéressé à savoir si ou non la tâche a déclenché une exception alors vous devez
await
le résultat, mais sur le revers de la médaille, c'est à peu près de défaites le but de "fire & oubliez".Dans le cas où vous voulez savoir si quelque chose mauvais qui s'est passé ensuite, la méthode recommandée est d'utiliser une continuation par exemple
await
appel surWorkAsync()
de l'intérieur d'uneasync
méthode. LeForget
méthode d'extension (qui ne fait rien) supprime l'avertissement parce que c'est un non-méthode asynchrone. Rendantasync
nouveau doit être ré-introduction de l'avertissement que vous êtes de retour à l'appel d'uneasync
méthode et ne pas appelerawait
(à moins que les méthodes d'extension sont traités différemment...).async void
donc il n'y a rien qui peut être attendu.throw t.Exception
vous pu "observer" en premier (var ignore = t.Exception;
et si pas acceptable, puis jeter:if(reallyBad) {throw t.Exception;}
Cela permet à l'acceptables pour être simplement avalé.Dans le lié à la question j'ai d'abord voulu utiliser
static void Forget(this Task task)
dans le contexte suivant:Il avait l'air super, mais j'ai réalisé que fatale exceptions éventuellement jetés par
_pendingTasks.Add
/_pendingTasks.Remove
serait passé inaperçu et a perdu, ce qui n'est pas bon.J'ai donc tout simplement fait
QueueTask
unasync void
méthode, ce qu'il consiste essentiellement à:Autant que je n'aime pas le vide
catch {}
, je pense qu'il fait sens ici.Dans ce scénario, en gardant
async Task QueueAsync()
et à l'aide deasync void Forget(this Task task)
comme vous proposez serait exagéré, de l'OMI.