1. ホーム
  2. c#

[解決済み] すべてのサーバーサイドのコードでConfigureAwaitを呼び出すためのベストプラクティス

2022-03-15 16:28:29

質問

サーバーサイドのコード(例えば、いくつかの ApiController を返すような非同期な関数を作成した場合、その関数は Task<SomeObject> - を呼び出すことは、ベストプラクティスと考えられています。 ConfigureAwait(false) ?

スレッドコンテキストの切り替えを元のスレッドコンテキストに戻す必要がないので、よりパフォーマンスが高いと読んだことがあります。 しかし、ASP.NET Web Apiでは、リクエストが1つのスレッドで受信され、何らかの関数を待機させながら ConfigureAwait(false) の最終結果を返すときに、別のスレッドに移動してしまう可能性があります。 ApiController 関数を使用します。

以下に、その例をタイプしてみました。

public class CustomerController : ApiController
{
    public async Task<Customer> Get(int id)
    {
        // you are on a particular thread here
        var customer = await GetCustomerAsync(id).ConfigureAwait(false);
        
        // now you are on a different thread!  will that cause problems?
        return customer;
    }
}

解決方法は?

更新してください。 ASP.NET Coreには SynchronizationContext . ASP.NET Coreであれば、以下のようにしても問題ありません。 ConfigureAwait(false) を使用するかどうか。

ASP.NET "Full"や"Classic"などの場合、この回答の残りの部分はそのまま適用されます。

元の投稿(非コアASP.NET用)。

ASP.NETチームによるこのビデオには、「Space」、「Space」、「Space」の使用に関する最良の情報が含まれています。 async をASP.NET上で使用することができます。

スレッドコンテキストを元のスレッドコンテキストに戻す必要がないため、よりパフォーマンスが高いと読んだことがあります。

これは、UI アプリケーションで、quot;sync" に戻らなければならない UI スレッドが 1 つだけである場合に当てはまります。

ASP.NETの場合、状況はもう少し複雑です。ASP.NETの場合 async メソッドの実行が再開されると、ASP.NET のスレッドプールからスレッドを取得します。を使用してコンテキスト・キャプチャを無効化すると ConfigureAwait(false) この場合、スレッドはメソッドを直接実行し続けるだけです。コンテキストキャプチャを無効にしない場合、スレッドはリクエストコンテキストに再入力し、メソッドの実行を継続します。

そこで ConfigureAwait(false) リクエストコンテキストを再入力する手間が省けますが、これは通常非常に高速です。 ConfigureAwait(false) かもしれない は、リクエストに対して少量の並列処理を行おうとする場合に便利ですが、実際には、そのようなシナリオのほとんどにTPLがより適しています。

<ブロッククオート

しかし、ASP.NET Web Apiでは、リクエストが1つのスレッドで受信され、何らかの関数を待ち、ConfigureAwait(false)を呼び出すと、ApiController関数の最終結果を返すときに別のスレッドに置かれる可能性があるのです。

実は await はそれができる。一度、あなたの async メソッドが await は、その メソッド はブロックされますが スレッド はスレッドプールに戻る。メソッドを続行する準備ができたら、スレッドプールから任意のスレッドを取り出し、メソッドを再開するために使用されます。

唯一の違いは ConfigureAwait ASP.NETでは、メソッドを再開するときに、そのスレッドがリクエストコンテキストに入るかどうかです。

背景については、私の に関するMSDN記事 SynchronizationContext と私の async イントロブログ記事 .