1. ホーム
  2. c#

[解決済み] Task.ConfigureAwait(continueOnCapturedContext: false)をわざわざ使う必要があるのか?

2023-06-26 14:38:08

疑問点

次のようなウィンドウズフォームのコードを考えてみましょう。

private async void UpdateUIControlClicked(object sender, EventArgs e)
{
    this.txtUIControl.Text = "I will be updated after await - i hope!";
    await Task.Delay(5000).ConfigureAwait(continueOnCapturedContext: false);
    this.txtUIControl.Text = "I am updated now.";
}

ここでは、3行目で例外が発生しています。これは、awaitの後に、UIでないスレッドでコードが実行されているためです。 ConfigureAwait(false)はどこで役に立つのでしょうか?

どのように解決するのですか?

Stephen Cleary は、この件に関して非常に優れたシリーズを持っており、ここで見ることができます。

Stephen Cleary はこのシリーズをとてもよく読んでいます。

たいていの場合、あなたは は必要ありません。 に同期する必要はありません。ほとんどの非同期メソッドは、合成を念頭に置いて設計されているでしょう。それらは他の操作を待ち、それぞれが非同期操作そのものを表します(他の操作によって合成することができます)。この場合、awaiter に次のように指示します。 ではなく を呼び出すことで、現在のコンテキストをキャプチャします。 構成待ち を呼び出し false を、例えば

private async Task DownloadFileAsync(string fileName)
{
  // Use HttpClient or whatever to download the file contents.
  var fileContents = await DownloadFileContentsAsync(fileName).ConfigureAwait(false);

  // Note that because of the ConfigureAwait(false), we are not on the original context here.
  // Instead, we're running on the thread pool.

  // Write the file contents out to a disk file.
  await WriteToDiskAsync(fileName, fileContents).ConfigureAwait(false);

  // The second call to ConfigureAwait(false) is not *required*, but it is Good Practice.
}

// WinForms example (it works exactly the same for WPF).
private async void DownloadFileButton_Click(object sender, EventArgs e)
{
  // Since we asynchronously wait, the UI thread is not blocked by the file download.
  await DownloadFileAsync(fileNameTextBox.Text);

  // Since we resume on the UI context, we can directly access UI elements.
  resultTextBox.Text = "File downloaded!";
}

この例で注意すべき重要な点は、非同期メソッド呼び出しの各「レベル」が独自のコンテキストを持っているということです。 DownloadFileButton_Click は UI コンテキストで開始し DownloadFileAsync . DownloadFileAsync も UI コンテキストで開始されましたが、その後に ConfigureAwait(false) . 残りの DownloadFileAsync はスレッドプールコンテキストで実行される。しかし DownloadFileAsync が完了し DownloadFileButton _Click が再開されると を行います。 UI コンテキストで再開します。

良い経験則は ConfigureAwait(false) ただし する はコンテキストが必要です。