次の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)はどこで役立ちますか?
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)
を使用することをお勧めします。
サービスはUIに依存しないため、サービスでは常に使用する必要があります。
ただし、次の場合はサービス以外で使用しないでください
このような場合、ConfigureAwait(false)
を使用しないでください。現在のコンテキストをキャプチャすることが重要です。そうしないと、非UIスレッドからUIビューにアクセスしようとするとアプリがクラッシュします
_await task;
_と書くと、await task.ConfigureAwait(true);
と書くのと同じです。したがって、デフォルトはtrueです。