1. ホーム
  2. c#

[解決済み] prevTask.Wait()はContinueWith(Tasksライブラリ)と併用することが推奨されていますか?

2023-04-20 02:55:06

質問

最近、私が使っていたタスクの.ContinueWithの使い方が適切でないと言われました。インターネット上でその証拠をまだ見つけていないので、皆さんに質問して、答えが何であるか見てみようと思います。以下は、私が.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");
    });
}

どのように解決するのですか?

えーっ...。現在の回答のいくつかは何かが欠けていると思います。例外が発生した場合はどうなるのでしょうか?

を呼び出す唯一の理由は Wait を呼び出す唯一の理由は、先行詞から例外が発生する可能性があることを 継続の中で観察するためでしょう。同じことが Result の場合 Task<T> にアクセスした場合、また、手動で Exception プロパティに手動でアクセスした場合も同様です。 正直なところ、私なら Wait を呼び出したり Result にアクセスするのは、例外が発生した場合にそれを再レイズする代償を支払うことになり、不必要なオーバーヘッドになるからです。その代わり、単に IsFaulted プロパティをチェックすればいいのです。 Task . また、成功か失敗のどちらかに基づいてのみ起動する複数の兄弟継続をチェーンすることで、 フォークされたワークフローを作成することもできます。 TaskContinuationOptions.OnlyOnRanToCompletionTaskContinuationOptions.OnlyOnFaulted .

さて、継続の際に先行詞の例外を観察する必要はありませんが、例えば "ステップ 1" が失敗した場合、ワークフローを先に進ませたくない場合があります。そのような場合: 指定した TaskContinuationOptions.NotOnFaulted を指定します。 ContinueWith を呼び出すと、継続ロジックが起動することさえできなくなります。

もし、あなた自身の継続が例外を観察しないなら、このワークフロー全体の完了を待っている人がそれを観察することになる、ということを心に留めておいてください。彼らは Wait を実行中であるか Task を使うか、自分自身の継続が完了したことを知るために、自分自身の 継続を付け足したか、どちらかです。もし後者であれば、その継続は前述の観測ロジックを使用する必要があります。