web-dev-qa-db-ja.com

prevTask.Wait()は、ContinueWith(Tasksライブラリから)と一緒に使用することをお勧めしますか?

そのため、最近、.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");
    });
}
88
Travyguy9

Ehhh ....現在の答えのいくつかは何かが欠けていると思います:例外はどうなりますか?

継続でWaitを呼び出す唯一の理由は、継続自体の前件からの潜在的な例外を観察することです。 Task<T>の場合にResultにアクセスした場合、およびExceptionプロパティに手動でアクセスした場合にも、同じ観察が行われます。率直に言って、Waitに電話したり、Resultにアクセスしたりすることはありません。例外がある場合は、不要なオーバーヘッドである再調達の代価を支払うからです。代わりに、前件IsFaultedTaskプロパティをチェックするだけです。または、TaskContinuationOptions.OnlyOnRanToCompletionおよびTaskContinuationOptions.OnlyOnFaultedで成功または失敗のいずれかに基づいてのみ起動する複数の兄弟の継続にチェーンすることにより、分岐したワークフローを作成できます。

これで、継続中の前件の例外を観察する必要はありませんが、たとえば「ステップ1」が失敗した場合、ワークフローを前進させたくない場合があります。その場合:TaskContinuationOptions.NotOnFaultedContinueWith呼び出しに指定すると、継続ロジックが起動するのを防ぐことができます。

独自の継続が例外を監視しない場合、このワークフロー全体の完了を待っている人がそれを監視することになります。 Wait上流のTaskingであるか、それがいつ完了したかを知るために独自の継続に取り組んでいます。後者の場合、継続するには前述の観測ロジックを使用する必要があります。

116
Drew Marsh

正しく使用しています。

ターゲットタスクの完了時に非同期的に実行する継続を作成します。

ソース: Task.ContinueWithメソッド(MSDNとしてのアクション)

Task.ContinueWith呼び出しごとにprevTask.Wait()を呼び出さなければならないことは、不必要なロジックを繰り返す奇妙な方法のようです。 。 ArgumentNullExceptionをスローするためにnullをチェックするようなもので、とにかくスローされるはずです。

だから、いや、それが間違っていると言った人は誰でも、おそらくTask.ContinueWithが存在する理由を理解していないだろう。

20
Anders Arpi

誰があなたにそれを言ったの?

引用 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");
    });
16
ken2k

MSDN on Task.Continuewithから

返されたタスクは、現在のタスクが完了するまで実行がスケジュールされません。 continuationOptionsパラメーターで指定された条件が満たされない場合、継続タスクはスケジュールされずにキャンセルされます。

最初の例であなたが期待する方法は正しい方法だと思います。

5
mclark1129

Task.Factory.StartNewの代わりにTask.Runの使用を検討することもできます。

Stephen Clearyの ブログ投稿 とStephen Toubの 彼が参照する投稿 は違いを説明しています。 this answer にも議論があります。

1
bizcad

Task.Resultにアクセスすると、実際にはtask.waitと同様のロジックを実行しています。

0
Sameh

すでに多くの人が話していることを繰り返しますが、prevTask.Wait()は不要です

より多くの例については、 Continuation Tasks を使用したタスクの連鎖にアクセスできます。Microsoftによる別のリンクも良い例です。

0
Amit Dash