59

後続のコードが呼び出し元の実行コンテキスト (UI スレッドである可能性がある) で実行されないように、ライブラリ コードでConfigureAwait(false)for sを使用することが推奨されることを理解しています。同じ理由で、の代わりに使用する必要があることawaitも理解しています。await Task.Run(CpuBoundWork)CpuBoundWork()

ConfigureAwait

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address).ConfigureAwait(false))
    using (var responseContent = httpResponse.Content)
    using (var contentStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false))
        return LoadHtmlDocument(contentStream); //CPU-bound
}

Task.Run

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address))
        return await Task.Run(async () =>
        {
            using (var responseContent = httpResponse.Content)
            using (var contentStream = await responseContent.ReadAsStreamAsync())
                return LoadHtmlDocument(contentStream); //CPU-bound
        });
}

これら2つのアプローチの違いは何ですか?

4

4 に答える 4

73

と言うときはTask.Run、長時間かかる可能性のある CPU 作業があることを意味しているため、常にスレッド プール スレッドで実行する必要があります。

と言うときConfigureAwait(false)、そのasyncメソッドの残りの部分は元のコンテキストを必要としないと言っています。ConfigureAwait最適化のヒントです。継続がスレッド プール スレッドで実行されるとは限りません

于 2013-02-16T03:07:41.143 に答える
16

この場合、最初の待機呼び出し( )は、呼び出しの結果と同様に呼び出しコンテキストにマーシャリングされるTask.Runため、バージョンのオーバーヘッドは少し多くなります。await client.GetAsync(address)Task.Run

一方、最初の例では、最初のAsync()メソッドは、呼び出し元のコンテキストにマーシャリングを戻す必要がないように構成されています。これにより、継続をバックグラウンドスレッドで実行できます。そのため、発信者のコンテキストに戻るマーシャリングはありません。

于 2013-02-16T02:10:00.463 に答える
3

@Stephen の回答に同意しました。まだ混乱している場合は、以下のスクリーンショット
を参照してください。 ここに画像の説明を入力

2# ConfigureAwait(false)
を使用して、ラベルを更新しようとしている下の画像作業スレッドを参照してください ここに画像の説明を入力

于 2017-05-07T05:03:24.213 に答える