Ainsi, on m'a dit récemment que la façon dont j'utilisais mon fichier .ContinueWith for Tasks n'était pas la bonne façon de les utiliser. Je n'ai pas encore trouvé de preuve de cela sur Internet, alors je vais vous demander de regarder la réponse. Voici un exemple d'utilisation de .ContinueWith:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}
Je sais maintenant qu’il s’agit d’un exemple simple et qu’il fonctionnera très vite, mais supposons simplement que chaque tâche effectue une opération plus longue. Donc, ce que l’on m’a dit, c’est que dans le fichier .ContinueWith, vous devez dire prevTask.Wait (); sinon, vous pourriez travailler avant la fin de la tâche précédente. Est-ce que c'est possible? J'ai supposé que mes deuxième et troisième tâches ne seraient exécutées qu'une fois leur tâche précédente terminée.
Ce qu'on m'a dit comment écrire le code:
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
prevTask.Wait();
Console.WriteLine("Step 3");
});
}
Ehhh .... Je pense que certaines des réponses actuelles manquent quelque chose: que se passe-t-il avec les exceptions?
La seule raison pour laquelle vous appelez Wait
dans une continuation est d'observer une exception potentielle de l'antécédent dans la continuation elle-même. La même observation se produirait si vous aviez accédé à Result
dans le cas d’un Task<T>
et aussi si vous aviez accédé manuellement à la propriété Exception
. Franchement, je n’appellerais pas Wait
ou accès Result
car s’il y avait une exception, vous payeriez prix de le relancer ce qui est des frais généraux inutiles. Au lieu de cela, vous pouvez simplement vérifier la propriété IsFaulted
de l'antécédent _Task
. Vous pouvez également créer des flux de travail définis en chaînant plusieurs chaînes consécutives qui ne sont déclenchées qu'en fonction du succès ou de l'échec avec TaskContinuationOptions.OnlyOnRanToCompletion
et TaskContinuationOptions.OnlyOnFaulted
.
Maintenant, il n'est pas nécessaire d'observer l'exception de l'antécédent dans la suite, mais vous ne souhaitez peut-être pas que votre flux de travail aille de l'avant si, par exemple, "Étape 1" a échoué. Dans ce cas: spécifier TaskContinuationOptions.NotOnFaulted
dans vos appels ContinueWith
empêcherait la logique de continuation de se déclencher.
Gardez à l'esprit que, si vos propres suites n'observent pas l'exception, la personne qui attend la fin de ce flux de travail global sera celle qui l'observera. Soit ils sont Wait
ing sur le Task
en amont, soit ont suivi leur propre continuation pour savoir quand il est terminé. Si c’est le dernier cas, leur continuation devra utiliser la logique d’observation susmentionnée.
Vous l'utilisez correctement.
Crée une continuation qui s'exécute de manière asynchrone lorsque la cible La tâche est terminée.
Source: Méthode Task.ContinueWith (Action en tant que MSDN)
Avoir à appeler prevTask.Wait()
dans chaque invocation Task.ContinueWith
apparaît comme un moyen étrange de répéter une logique inutile - c’est-à-dire faire quelque chose pour être "ultra-sûr" parce que vous ne comprenez pas réellement ce que fait un certain code. C'est comme vérifier un zéro pour lancer une ArgumentNullException
où il aurait été jeté de toute façon.
Donc, non, celui qui vous a dit que c'était faux et ne comprend probablement pas pourquoi Task.ContinueWith
existe.
Qui t'as dit ça?
Citant _ MSDN :
Crée une continuation qui s'exécute de manière asynchrone lorsque la cible La tâche est terminée.
Aussi, quel serait le but de Continuer avec s'il n'attendait pas la tâche précédente?
Vous pouvez même le tester vous-même:
Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
Thread.Sleep(2000);
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("I waited step 1 to be completed!");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
À partir du MSDN on Task.Continuewith
La tâche renvoyée ne sera pas planifiée pour être exécutée avant le la tâche en cours est terminée. Si les critères spécifiés par le Les options continuationOptions ne sont pas remplies, la tâche de continuation sera être annulé au lieu de prévu.
Je pense que la manière dont vous vous attendez à ce que cela fonctionne dans le premier exemple est la bonne.
Vous pouvez également envisager d’utiliser Task.Run au lieu de Task.Factory.StartNew.
Stephen Cleary article de blog et l'article de Stephen Toub qu'il référence explique les différences Il y a aussi une discussion dans cette réponse .
En accédant à Task.Result
, vous utilisez une logique similaire à celle de task.wait
Je répète ce que beaucoup ont déjà dit, prevTask.Wait()
est inutile.
Pour plus d'exemples, vous pouvez aller à Chaînage de tâches à l'aide de tâches de continuation , autre lien fourni par Microsoft avec de bons exemples.