88

So I was told recently that how I was using my .ContinueWith for Tasks was not the proper way to use them. I have yet to find evidence of this on the internet so I will ask you guys and see what the answer is. Here is an example of how I use .ContinueWith:

public Task DoSomething()
{
    return Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Step 1");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 2");
    })
    .ContinueWith((prevTask) =>
    {
        Console.WriteLine("Step 3");
    });
}

Now I know this is a simple example and it will run very fast, but just assume each task does some longer operation. So, what I was told is that in the .ContinueWith, you need to say prevTask.Wait(); otherwise you could do work before the previous task finishes. Is that even possible? I assumed my second & third task would only run once their previous task finishes.

What I was told how to write the 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");
    });
}
4

7 に答える 7

116

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

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

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

あなた自身の継続が例外を観察しない場合、この全体的なワークフローが完了するのを待っている人がそれを観察することになることに注意してください。彼らはアップストリームに取り組んでいるか、それがいつ完了WaitするTaskかを知るために独自の継続に取り組んでいます。後者の場合、それらの継続には前述の観察ロジックを使用する必要があります。

于 2012-08-10T17:56:21.963 に答える
20

あなたはそれを正しく使用しています。

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

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

呼び出しprevTask.Wait()ごとにTask.ContinueWith呼び出さなければならないというのは、不必要なロジックを繰り返す奇妙な方法のように思えます。つまり、特定のコードが何をするのかを実際に理解していないため、「非常に確実」に何かを行うことです。ArgumentNullExceptionとにかくスローされたはずの場所にスローするためだけにnullをチェックするようなものです。

だから、いや、それは間違っていると言った人は誰でも、なぜTask.ContinueWith存在するのか理解していないでしょう.

于 2012-08-10T15:32:28.917 に答える
16

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

MSDNを引用:

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

また、前のタスクが完了するのを待っていなかった場合、 Continue Withの目的は何でしょうか?

自分でテストすることもできます:

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");
    });
于 2012-08-10T15:34:53.207 に答える
5

MSDNから_Task.Continuewith

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

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

于 2012-08-10T15:32:44.990 に答える
0

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

于 2015-09-17T15:34:53.137 に答える