web-dev-qa-db-ja.com

なぜわざわざTask.ConfigureAwait(continueOnCapturedContext:false);

次のWindowsフォームのコードを検討してください。

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

ここでは、待機後、コードが非UIスレッドで実行されるため、3行目に例外がスローされます。 ConfigureAwait(false)はどこで役立ちますか?

55
Yawar Murtaza

Stephen Clearyにはこれに関する非常に優れたシリーズがあります 、あなたの質問に特有の部分を引用しました:

ほとんどの場合、「メイン」コンテキストに同期する必要はありません。ほとんどの非同期メソッドは、構成を念頭に置いて設計されます。他の操作を待機し、各メソッドは非同期操作自体を表します(他の人が構成できます)。この場合は、ConfigureAwaitを呼び出して、現在のコンテキストをnotキャプチャするように待機者に伝えたい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コンテキストでdoes再開します。

経験則として、コンテキストが必要doでない限り、ConfigureAwait(false)を使用することをお勧めします。

79
Victor Learned

サービスはUIに依存しないため、サービスでは常に使用する必要があります。

ただし、次の場合はサービス以外で使用しないでください

  • uIを操作するか、DispatcherやCoreDispatcherなどのUI固有のコンポーネントを使用する必要がある
  • aSP.netでHttpClient.Currentを使用する必要があります

このような場合、ConfigureAwait(false)を使用しないでください。現在のコンテキストをキャプチャすることが重要です。そうしないと、非UIスレッドからUIビューにアクセスしようとするとアプリがクラッシュします

_await task;_と書くと、await task.ConfigureAwait(true);と書くのと同じです。したがって、デフォルトはtrueです。

1
pixel