public async Task Foo()
同期メソッドから呼び出したいメソッドがあります。 これまで MSDN ドキュメントで確認したのは、メソッドasync
経由でメソッドを呼び出すことasync
だけですが、プログラム全体がasync
メソッドで構築されているわけではありません。
そんなことが可能なのでしょうか?
非同期メソッドからこれらのメソッドを呼び出す例を次に示します。
チュートリアル: Async と Await を使用して Web にアクセスする (C# および Visual Basic)
async
現在、これらのメソッドを同期メソッドから呼び出すことを検討しています。
ベストアンサー1
非同期プログラミングはコードベースを通じて「成長」します。ゾンビウイルスと比較すると最善の解決策は成長させることですが、それが不可能な場合もあります。
私はいくつかのタイプを書いてきましたNito.AsyncEx部分的に非同期のコード ベースを処理するためのライブラリ。ただし、あらゆる状況で機能するソリューションはありません。
解決策A
コンテキストに同期する必要のない単純な非同期メソッドがある場合は、次を使用できますTask.WaitAndUnwrapException
。
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
またはは例外を でラップするため、使用しないでください。Task.Wait
Task.Result
AggregateException
このソリューションは、 がそのコンテキストに同期しない場合にのみ適切ですMyAsyncMethod
。つまり、await
のすべてのMyAsyncMethod
は で終わる必要がありますConfigureAwait(false)
。つまり、UI 要素を更新したり、ASP.NET 要求コンテキストにアクセスしたりすることはできません。
解決策B
MyAsyncMethod
コンテキストに同期する必要がある場合は、 を使用してAsyncContext.RunTask
ネストされたコンテキストを提供できる場合があります。
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
*2014 年 4 月 14 日更新: ライブラリの最新バージョンでは、API は次のようになります。
var result = AsyncContext.Run(MyAsyncMethod);
(例外が伝播されるTask.Result
ため、この例では使用しても問題ありません)。RunTask
Task
AsyncContext.RunTask
の代わりに が必要になる理由は、Task.WaitAndUnwrapException
WinForms/WPF/SL/ASP.NET で発生する、かなり微妙なデッドロックの可能性があるためです。
- 同期メソッドは非同期メソッドを呼び出し、を取得します
Task
。 - 同期メソッドは、 に対してブロッキング待機を実行します
Task
。 - メソッドはwithout を
async
使用します。await
ConfigureAwait
- この状況では は完了できません。これは、 メソッドが終了した
Task
ときにのみ完了するためです。メソッドは への継続を にスケジュールしようとしているため完了できません。また、同期メソッドがそのコンテキストで既に実行されているため、WinForms/WPF/SL/ASP.NET では継続の実行が許可されません。async
async
SynchronizationContext
これは、可能な限りConfigureAwait(false)
すべてのメソッド内で使用することを推奨する理由の 1 つです。async
解決策C
AsyncContext.RunTask
すべてのシナリオで機能するわけではありません。たとえば、メソッドが UI イベントの完了を必要とする何かを待機している場合、ネストされたコンテキストでもデッドロックが発生します。その場合は、スレッド プールでメソッドasync
を開始できます。async
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
ただし、このソリューションには、スレッド プール コンテキストで動作する が必要です。そのため、UI 要素を更新したり、ASP.NET 要求コンテキストにアクセスしたりすることはできません。その場合は、ステートメントに追加して、ソリューション A を使用することMyAsyncMethod
もできます。ConfigureAwait(false)
await
更新: 2015 MSDN記事 '非同期プログラミング - ブラウンフィールド非同期開発' スティーブン・クリアリー著。