web-dev-qa-db-ja.com

await Task <T>とTask <T> .Resultの違いは何ですか?

 public async Task<string> GetName(int id)
    {
        Task<string> nameTask =
            Task.Factory.StartNew(() => { return string.Format("Name matching id {0} = Developer", id); });
        return nameTask.Result;
    }

上記のメソッドreturnステートメントでは、Task.Resultプロパティを使用しています。

public async Task<string> GetName(int id)
    {
        Task<string> nameTask =
            Task.Factory.StartNew(() => { return string.Format("Name matching id {0} = Developer", id); });
        return await nameTask;
    }

ここでは、待機タスクを使用しています。 awaitが呼び出しスレッドを解放すると思っても、Task.Resultがそれをブロックすると思っても間違いはありませんか?

48
Yawar Murtaza

Awaitが呼び出しスレッドを解放すると思っても、Task.Resultがそれをブロックすると思っても間違いはありませんか?

通常、はい。 await task;は現在のスレッドを「譲ります」。 task.Resultは現在のスレッドをブロックします。 awaitは非同期待機です。 Resultはブロッキング待機です。

さらに小さな違いがもう1つあります。タスクが障害状態(つまり、例外あり)で完了した場合、awaitはその例外をそのまま(再)発生させますが、ResultはラップしますAggregateExceptionの例外。

補足として、Task.Factory.StartNew。ほとんどの場合、正しい方法ではありません。バックグラウンドスレッドで作業を実行する必要がある場合は、Task.Run

動的タスクの並列処理 ;を実行している場合、ResultStartNewの両方が適切です。それ以外の場合は、回避する必要があります。 非同期プログラミング を実行している場合、どちらも適切ではありません。

48
Stephen Cleary

Awaitが呼び出しスレッドを解放すると思っても、Task.Resultがそれをブロックすると思っても間違いはありませんか?

タスクが同期的に完了していない限り、あなたは正しいです。その場合、awaitは最初にタスクが完了したかどうかをチェックするため、_Task.Result_または_await task_のいずれかを使用すると、同期的に実行されます。それ以外の場合、タスクが完了していない場合、awaitを使用すると_Task.Result_の呼び出しスレッドがブロックされますa同期してタスクの完了を待ちます。異なるもう1つの点は、例外処理です。前者はAggregationException(1つ以上の例外を含む可能性があります)を伝播しますが、後者はそれをアンラップして、基になる例外を返します。

補足として、 syncメソッドで非同期ラッパーを使用することは悪い習慣であり、回避する必要があります。 また、非同期メソッド内で_Task.Result_を使用すると、デッドロックが発生し、また避けてください。

4
Yuval Itzchakov