単一のメソッド内で同期メソッドと非同期メソッドを効率的に混合しますか?


11

さて、奇妙に聞こえますが、コードは非常にシンプルで、状況をうまく説明しています。

public virtual async Task RemoveFromRoleAsync(AzureTableUser user, string role)
{
    AssertNotDisposed();
    var roles = await GetRolesForUser(user);
    roles.Roles = RemoveRoles(roles.Roles, role);
    await Run(TableOperation.Replace(roles));
}

(私は以下の要約で話していることを知っていますが、上記は私がここで尋ねていることを実際に実行している実際の生産コードになるものからの実際の方法であり、実際にレビューすることに興味があります非同期/待機パターンに対する正確さのため)

async/ を使用しているため、このパターンに頻繁に遭遇していawaitます。このパターンは、次の一連のイベントで構成されています。

  1. 作業に必要な情報を取得する最初の電話を待つ
  2. その情報を同期的に処理する
  3. 更新された作業を保存する最後の呼び出しを待つ

通常、上記のコードブロックは、これらのメソッドの処理方法です。私awaitは最初の呼び出しです。非同期であるためです。次に、IOまたはリソースにバインドされていないため、非同期ではない、必要な作業を実行します。最後に、私はまた、ある私の仕事、保存async、および貨物カルトIのうち呼び出しawait、それを。

しかし、これはこのパターンを処理する最も効率的で正しい方法ですか?私awaitは最後の呼び出しをスキップすることができたようですが、それが失敗したらどうなりますか?また、同期作業を元の呼び出しと連鎖さTaskせるなどの方法を使用する必要がありContinueWithますか?私はちょうど今これを正しく処理しているかどうかわからない時点にいます。

例のコードを考えると、この非同期/同期/非同期メソッド呼び出しチェーンを処理するより良い方法はありますか?


コードはできるだけ短く理解しやすいように思えます。私が考えることができるものはすべて、不必要な複雑さをもたらします。
陶酔14年

@Euphoric:最後の電話をわざわざ待つ必要がありますか?そうしなかった場合、どうなりますか?現在のように何か違うのでしょうか?
食い物

回答:


3

はい、これが正しい方法だと思います。

2つ目をスキップすることはできませんawait。削除した場合、メソッドは完了が早すぎる(削除が実際に行われる前)ように見えるため、削除が失敗したかどうかはわかりません。

ContinueWith()ここでどのように役立つか、またはそのようなものは見当たりません。を使用して回避することもできますawaitが、コードがより複雑になり、読みにくくなります。それが、await継続の使用と比較した場合の非同期コードの記述を簡単にすることの重要なポイントです。


0

このパターンを処理する方法は、すべてのI / Oが非同期であることを確認することです。同期I / Oメソッドは、I / O宛先(ネットワーク、ファイルシステムなど)からの応答を待機している間、現在のスレッドをブロックします。

考慮awaitすべきもう1つのことは、戻り値が必要な場合、または他の処理を行う前に待機コードを終了する必要がある場合に使用することです。これらのいずれも必要ない場合は、非同期メソッドを「発火して忘れる」ことができますTask.Run

そのため、コンピューティングリソースを最も効率的に使用するにRemoveRolesは、I / Oを行う場合、I / Oになる必要がawait RemoveRolesAsyncあり、呼び出されるI / OメソッドRemoveRolesAsyncも非同期である必要があります。

パフォーマンスが最大の懸念事項でない場合は、非同期スレッドで同期I / Oを実行しても問題ありません。しかし、それは技術的な負債です。(この場合、コードの実行場所に応じて、を使用して最初の非同期メソッドを呼び出すことができますConfigureAwait。)

ベストプラクティスの詳細をご覧ください-https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

ASP.NET、WebAPIなどのさまざまな環境でのConfigureAwaitの動作に関するいくつかの注意事項があります-https ://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side -コード


2
Task.Runでコードを起動したり忘れたりしないでください。すべてのタスクを待つ必要があります。タスクを待たずに、例外が「未観察」の状態でタスクがガベージコレクションされると、ランタイムでUnobservedTaskExceptionが発生し、フレームワークのバージョンによってはアプリケーションがクラッシュする可能性があります。
トリインコ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.