最近、多くの非同期メソッドを使用するコードを読んでいましたが、それらを同期的に実行する必要がある場合があります。コードは:
Foo foo = GetFooAsync(...).GetAwaiter().GetResult();
これは同じですか
Foo foo = GetFooAsync(...).Result;
async/ awaitメソッド)
最近、多くの非同期メソッドを使用するコードを読んでいましたが、それらを同期的に実行する必要がある場合があります。コードは:
Foo foo = GetFooAsync(...).GetAwaiter().GetResult();
これは同じですか
Foo foo = GetFooAsync(...).Result;
async/ awaitメソッド)
回答:
かなり。ただし、小さな違いが1つあります。Task失敗した場合、GetResult()直接発生した例外がスローされるだけで、Task.ResultはスローされますAggregateException。ただし、どちらを使用するのasyncですか?100倍良いオプションはを使用することawaitです。
また、を使用するためのものではありませんGetResult()。それはあなたのためではなく、コンパイラの使用のみを目的としています。しかし、迷惑なものAggregateExceptionにしたくない場合は、それを使用してください。
async Taskしており、しばらくは使用できます。
The 100x better option is to use await.私はこのような発言が嫌いです、もし私がawaitそれの前で平手打ちできたら私はそうします。私は頻繁に私に何が起こるかのような非非同期コードに対する作業に非同期コードを取得しようとしているときには、多くのことを Xamarinには、私のようなものを使用する必要が終わるContinueWithそれがUIをデッドロックではないようにするために多くの。編集:私はこれが古いことを知っていますが、それだけでは使用できない状況に代わるものがなく、これを述べている答えを見つける私の欲求不満を軽減しませんawait。
Task.GetAwaiter().GetResult()好まれるTask.WaitとTask.Result、それはそれらをラップするのではなく、例外を伝播しているためAggregateException。ただし、3つすべての方法では、デッドロックとスレッドプール不足の問題が発生する可能性があります。彼らはすべてを支持して避けるべきですasync/await。
以下の引用は、理由Task.Waitを説明しておりTask.Result、Task.GetAwaiter().GetResult()(「非常に高い互換性バー」による)の例外伝播動作を単純に含んでいない。
先に述べたように、互換性バーが非常に高いため、変更を壊すことは避けました。そのため、
Task.Wait常に折り返すという元の動作を保持します。ただし、で採用されている同期ブロッキングと同様の動作Task.Waitが必要であるが、元の例外がに含まれるのではなく、ラップされずに伝播されることが必要な場合がありますAggregateException。それを達成するために、タスクのウェイターを直接ターゲットにすることができます。「await task;」を書き込むと、コンパイラはそれをTask.GetAwaiter()メソッドの使用法に変換し、メソッドを持つインスタンスを返しますGetResult()。障害のあるタスクで使用GetResult()すると、元の例外が伝播されます(これにより、「await task;」が動作します)。したがって、「task.GetAwaiter().GetResult()この伝播ロジックを直接呼び出したい場合。
https://blogs.msdn.microsoft.com/pfxteam/2011/09/28/task-exception-handling-in-net-4-5/
「
GetResult」は実際には「タスクのエラーをチェックする」という意味です一般的に、非同期タスクでの同期ブロックを回避するために最善を尽くしています。ただし、そのガイドラインに違反している状況がいくつかあります。これらのまれな状況では
GetAwaiter().GetResult()、タスクの例外をでラップするのではなく保存するため、私が推奨する方法ですAggregateException。
http://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html
Task.GetAwaiter().GetResult()はと同等await taskです。メソッドをマークできない場合async(コンストラクタなど)、最初のオプションが使用されると思います。あれは正しいですか?はいの場合、それはトップの回答@ It'sNotALie
Task.GetAwaiter().GetResult()はTask.Waitandと同等ですがTask.Result(3つすべてが同期的にブロックされ、デッドロックの可能性がありTask.GetAwaiter().GetResult()ます)、awaitタスクの例外伝播動作があります。
https://github.com/aspnet/Security/issues/59
「最後の一つの発言:あなたが使用して避けなければならない
Task.ResultとTask.Wait、彼らは常にで内部例外をカプセル化するようできるだけAggregateExceptionと難しく、デバッグになり、一般的な1(1つの以上のエラーが発生した)、でメッセージを交換する場合でも、同期バージョンshouldn。頻繁に使用しないでくださいTask.GetAwaiter().GetResult()。代わりに使用することを強く検討する必要があります。」
Task.WhenAll(task1, task2).GetAwaiter().GetResult();。
もう1つの違いは、async関数が次のTask代わりに戻るTask<T>場合です。
GetFooAsync(...).Result;
一方
GetFooAsync(...).GetAwaiter().GetResult();
まだ動作します。
質問のコード例はケース用であることはわかっていますが、質問はTask<T>一般的に行われます。
Resultwith GetIntAsync()を使用してTask<int>、だけでなくも返しますTask。私の答えをもう一度読むことをお勧めします。
GetFooAsync(...).Result 中に入れることはできないとあなたが答えると理解したTask。C#にTask.Resultはvoidプロパティがないため(これはプロパティです)、これは当然のことですが、もちろんvoidメソッドを呼び出すことができます。
あなたが使用できるかどうかすでに述べたようにawait。あなたが言及するようにコードを同期的に実行する必要がある場合.GetAwaiter().GetResult()、.Resultまたは.Wait()多くの人がコメント/回答で述べているようにデッドロックのリスクがある場合。私たちの多くはワンライナーが好きなので、これらを次の用途に使用できます.Net 4.5<
非同期メソッドを介して値を取得する:
var result = Task.Run(() => asyncGetValue()).Result;
非同期メソッドを同期的に呼び出す
Task.Run(() => asyncMethod()).Wait();
の使用によるデッドロックの問題は発生しませんTask.Run。
ソース:
タスクが失敗した場合、継続コードがawaiter.GetResult()を呼び出すと、例外が再スローされます。GetResultを呼び出すのではなく、タスクのResultプロパティにアクセスするだけで済みます。GetResultを呼び出すことの利点は、タスクが失敗した場合、例外がAggregateExceptionにラップされずに直接スローされるため、よりシンプルでクリーンなcatchブロックが可能になることです。
非ジェネリックタスクの場合、GetResult()にはvoidの戻り値があります。その場合、その便利な機能は、例外を再スローすることだけです。
ソース:簡単に言うとc#7.0
GetResult:「この型とそのメンバーはコンパイラによる使用を目的としています。」他の人はそれを使うべきではありません。