Gérer de façon élégante l'annulation de tâches
Lors de l'utilisation de tâches pour les gros/long cours d'exécution des charges de travail que j'ai besoin d'être en mesure de l'annuler, j'utilise souvent un modèle similaire à ce que l'action la tâche s'exécute:
public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
Log.Exception(ex);
throw;
}
}
La OperationCanceledException ne doit pas être enregistré comme une erreur, mais il ne doit pas être avalé si la tâche est de faire la transition vers l'annulation de l'état. Toutes les autres exceptions ne doivent pas être traitées au-delà de la portée de cette méthode.
Ce toujours senti un peu maladroit, et visual studio, par défaut, pause sur le lancer pour OperationCanceledException (Bien que j'ai une pause de l'Utilisateur-non gérée " éteint maintenant pour OperationCanceledException à cause de mon utilisation de ce modèle).
Idéalement, je pense que j'aimerais être capable de faire quelque chose comme ceci:
public void DoWork(CancellationToken cancelToken)
{
try
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
catch (Exception ex) exclude (OperationCanceledException)
{
Log.Exception(ex);
throw;
}
}
c'est à dire avoir une sorte de liste d'exclusion appliquée à la capture, mais sans le support de la langue qui n'est pas possible actuellement (@eric-lippert: c# vNext fonctionnalité :)).
Un autre moyen serait par le biais d'une poursuite:
public void StartWork()
{
Task.Factory.StartNew(() => DoWork(cancellationSource.Token), cancellationSource.Token)
.ContinueWith(t => Log.Exception(t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
}
public void DoWork(CancellationToken cancelToken)
{
//do work
cancelToken.ThrowIfCancellationRequested();
//more work
}
mais je n'aime pas vraiment que l'exception peut techniquement avoir plus qu'une seule exception interne et vous n'avez pas autant de contexte lors de la connexion de l'exception comme vous le feriez dans le premier exemple (si je faisais plus que juste de l'enregistrement).
Je comprends que c'est un peu une question de style, mais vous vous demandez si quelqu'un a une meilleure suggestion?
Dois-je rester avec l'exemple 1?
Eamon
- J'utilise une solution où la structure de journalisation faire des choses différentes pour certaines exceptions. c'est à dire ignorer OperationCancelledException, aplatit AggregateException, des journaux uniquement innerException pour InvalidOperationException etc
Vous devez vous connecter pour publier un commentaire.
Donc, quel est le problème? Jeter de la
catch (OperationCanceledException)
bloc, et de définir la bonne continuations:TPL distingue de l'annulation et de la faute. Par conséquent, l'annulation (c'est à dire lancer
OperationCancelledException
cadre de la task corps) n'est pas une faute.Le point principal: ne pas gérer les exceptions dans la tâche corps sans re-jeter.
try-catch-throw
.Ici est de savoir comment vous gérer de façon élégante l'annulation de Tâches:
Manipulation "fire-and-forget" Tâches
Manipulation attendent l'achèvement de la Tâche /annulation
C# 6.0 a une solution pour cela..Filtrage d'exception
Selon ce blog MSDN, vous devez attraper
OperationCanceledException
, par exempleVous pourriez faire quelque chose comme ceci:
Je ne suis pas entièrement sûr de ce que vous essayez d'atteindre d'ici, mais je pense que le modèle suivant peut aider à
Vous avez pu le constater, que j'ai supprimé l'instruction throw à partir d'ici. Ce ne sera pas jeter l'exception mais tout simplement de l'ignorer.
Laissez-moi savoir si vous avez l'intention de faire quelque chose d'autre.
Il y a encore une autre façon qui est assez proche de ce que vous avez exposé dans votre code
catch (OperationCanceledException) {}
sera de définir la tâche du statutRanToCompletion
, pas commeCanceled
. Il y a des cas d'utilisation, lorsque cette différence est importante.