[解決済み] C#で同期メソッドから非同期メソッドを呼び出すには?
質問
私は
public async void Foo()
メソッドを呼び出したい。これまでのところ、私がMSDNドキュメントから見たのは、非同期メソッドを介して非同期メソッドを呼び出すことだけですが、私のプログラム全体は非同期メソッドで構築されていません。
このようなことは可能なのでしょうか?
これらのメソッドを非同期メソッドから呼び出す例を一つ紹介します。
チュートリアル 非同期とAwaitを使ったウェブアクセス(C#とVisual Basic)
さて、これらの非同期メソッドを同期メソッドから呼び出すことを検討しています。
どのように解決するのですか?
非同期プログラミングは、コードベースを通して成長します。それは ゾンビウィルスに例えられる . 一番の解決策は、成長を許すことですが、そうもいかない場合もあります。
の中にいくつかの型を書きました。 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
. -
は
async
メソッドではawait
なしConfigureAwait
. -
は
Task
のときにしか完了しないので、この状況では完了することができません。async
メソッドが終了します。async
メソッドが完了できないのは、その継続をSynchronizationContext
そして、WinForms/WPF/SL/ASP.NET はそのコンテキストで同期メソッドが既に実行されているため、継続の実行を許可しない。
このようなこともあり、このような場合は
ConfigureAwait(false)
をすべての
async
メソッドをできるだけ多く使用します。
解決策C
AsyncContext.RunTask
は、すべてのシナリオで機能するわけではありません。例えば、もし
async
メソッドは、UI イベントを完了させるために必要な何かを待っているのですが、その場合、ネストされたコンテキストでもデッドロックが発生します。そのような場合は
async
メソッドをスレッドプールで実行します。
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
しかし、この解決策では
MyAsyncMethod
スレッドプールのコンテキストで動作します。そのため、UI要素の更新やASP.NETのリクエストコンテキストにアクセスすることができません。そして、その場合は、スレッドプールコンテキストで動作するように
ConfigureAwait(false)
をその
await
ステートメントを作成し、解決策Aを使用します。
2019-05-01に更新しました。 現在の"restorward practices"は、以下の通りです。 MSDN記事はこちら .
関連
-
[解決済み] enumを列挙するには
-
[解決済み] intをenumにキャストするにはどうすればよいですか?
-
[解決済み] 辞書を繰り返し使用するには?
-
[解決済み] async」と「await」の使い方とタイミング
-
[解決済み] リフレクションを使ってジェネリックメソッドを呼び出すにはどうしたらいいですか?
-
[解決済み] あるコンストラクタを別のコンストラクタから呼び出す
-
[解決済み] C#でawaitを使わずに非同期メソッドを安全に呼び出す方法
-
[解決済み】非同期処理の待ち時間、Wait()でプログラムがフリーズする原因はここにある
-
[解決済み】C#でValueTask<T>ではなくTask<T>を使用するのはなぜですか?
-
[解決済み] この呼び出しが待機されていないことを警告し、現在のメソッドの実行を継続します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] [Solved] 1つ以上のエンティティで検証に失敗しました。詳細は'EntityValidationErrors'プロパティを参照してください [重複]。
-
[解決済み] 保護レベルによりアクセス不能になりました。
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み】EF 5 Enable-Migrations : アセンブリにコンテキストタイプが見つかりませんでした
-
[解決済み] EntityTypeにキーが定義されていないエラー
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み] ...基礎となる接続は閉じられました。予期しないエラーが受信で発生しました
-
[解決済み】 C# 条件演算子エラー 代入、call、increment、decrement、await、new object 式のみ文として使用可能です。
-
[解決済み】別のスレッドがこのオブジェクトを所有しているため、呼び出し側のスレッドはこのオブジェクトにアクセスできない
-
[解決済み】WebResource.axdとは何ですか?