そのため、最近、.ContinueWith for Tasksをどのように使用するのが適切な使用方法ではないと言われました。私はまだインターネットでこれの証拠を見つけていないので、皆さんに尋ねて、答えが何であるかを見ます。次に、.ContinueWithの使用例を示します。
public Task DoSomething()
{
return Task.Factory.StartNew(() =>
{
Console.WriteLine("Step 1");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 2");
})
.ContinueWith((prevTask) =>
{
Console.WriteLine("Step 3");
});
}
これは簡単な例であり、非常に高速に実行されることはわかっていますが、各タスクがより長い操作を行うと仮定してください。ですから、.ContinueWithでprevTask.Wait();と言う必要があると言われました。そうしないと、前のタスクが完了する前に作業を行うことができます。それも可能ですか? 2番目と3番目のタスクは、前のタスクが終了した後にのみ実行されると想定しました。
コードの書き方を教えられました:
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 ....現在の答えのいくつかは何かが欠けていると思います:例外はどうなりますか?
継続でWait
を呼び出す唯一の理由は、継続自体の前件からの潜在的な例外を観察することです。 Task<T>
の場合にResult
にアクセスした場合、およびException
プロパティに手動でアクセスした場合にも、同じ観察が行われます。率直に言って、Wait
に電話したり、Result
にアクセスしたりすることはありません。例外がある場合は、不要なオーバーヘッドである再調達の代価を支払うからです。代わりに、前件IsFaulted
のTask
プロパティをチェックするだけです。または、TaskContinuationOptions.OnlyOnRanToCompletion
およびTaskContinuationOptions.OnlyOnFaulted
で成功または失敗のいずれかに基づいてのみ起動する複数の兄弟の継続にチェーンすることにより、分岐したワークフローを作成できます。
これで、継続中の前件の例外を観察する必要はありませんが、たとえば「ステップ1」が失敗した場合、ワークフローを前進させたくない場合があります。その場合:TaskContinuationOptions.NotOnFaulted
をContinueWith
呼び出しに指定すると、継続ロジックが起動するのを防ぐことができます。
独自の継続が例外を監視しない場合、このワークフロー全体の完了を待っている人がそれを監視することになります。 Wait
上流のTask
ingであるか、それがいつ完了したかを知るために独自の継続に取り組んでいます。後者の場合、継続するには前述の観測ロジックを使用する必要があります。
正しく使用しています。
ターゲットタスクの完了時に非同期的に実行する継続を作成します。
ソース: Task.ContinueWithメソッド(MSDNとしてのアクション)
Task.ContinueWith
呼び出しごとにprevTask.Wait()
を呼び出さなければならないことは、不必要なロジックを繰り返す奇妙な方法のようです。 。 ArgumentNullException
をスローするためにnullをチェックするようなもので、とにかくスローされるはずです。
だから、いや、それが間違っていると言った人は誰でも、おそらくTask.ContinueWith
が存在する理由を理解していないだろう。
誰があなたにそれを言ったの?
引用 MSDN :
ターゲットタスクの完了時に非同期的に実行される継続を作成します。
また、Continueの目的は何でしょうか?前のタスクが完了するのを待っていなかった場合は?
自分でテストすることもできます:
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");
});
MSDN on Task.Continuewith
から
返されたタスクは、現在のタスクが完了するまで実行がスケジュールされません。 continuationOptionsパラメーターで指定された条件が満たされない場合、継続タスクはスケジュールされずにキャンセルされます。
最初の例であなたが期待する方法は正しい方法だと思います。
Task.Factory.StartNewの代わりにTask.Runの使用を検討することもできます。
Stephen Clearyの ブログ投稿 とStephen Toubの 彼が参照する投稿 は違いを説明しています。 this answer にも議論があります。
Task.Result
にアクセスすると、実際にはtask.wait
と同様のロジックを実行しています。
すでに多くの人が話していることを繰り返しますが、prevTask.Wait()
は不要です。
より多くの例については、 Continuation Tasks を使用したタスクの連鎖にアクセスできます。Microsoftによる別のリンクも良い例です。