最近、多くの非同期メソッドを使用するコードを読んでいましたが、それらを同期的に実行する必要がある場合があります。コードは:
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.Wait
andと同等ですが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>
一般的に行われます。
Result
with 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
:「この型とそのメンバーはコンパイラによる使用を目的としています。」他の人はそれを使うべきではありません。