Ответ 1
У Стивена Клири есть действительно хорошая серия по этому, вы можете найти здесь, я процитировал часть, специфичную для вашего вопроса:
В большинстве случаев вам не нужно синхронизироваться с "основным" контекстом. Большинство асинхронных методов будут разрабатываться с учетом композиции: они ожидают других операций, и каждый из них представляет саму асинхронную операцию (которая может быть составлена другими). В этом случае вы хотите сообщить ожидающему, чтобы он не захватывал текущий контекст, вызвав ConfigureAwait и передав
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
запускается в контексте пользовательского интерфейса и называетсяDownloadFileAsync
.DownloadFileAsync
также запускался в контексте пользовательского интерфейса, но затем выходил из его контекста, вызываяConfigureAwait(false)
. Остальная частьDownloadFileAsync
выполняется в контексте пула потоков. Однако, когдаDownloadFileAsync
завершается иDownloadFileButton
_Click возобновляется, он возобновляется в контексте пользовательского интерфейса.Хорошее практическое правило - использовать
ConfigureAwait(false)
если вы не знаете, что вам нужен контекст.