Подтвердить что ты не робот

Почему я должен использовать Task.ConfigureAwait(continueOnCapturedContext: false);

Рассмотрим следующий код оконных форм:

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. Где ConfigureAwait (false) полезно?

4b9b3361

Ответ 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) если вы не знаете, что вам нужен контекст.

Ответ 2

Вы должны всегда использовать его в сервисах, поскольку сервисы не должны зависеть от пользовательского интерфейса.

Однако не используйте его вне сервисов, если

  • необходимо манипулировать пользовательским интерфейсом или использовать определенные компоненты пользовательского интерфейса, такие как Dispatcher или CoreDispatcher
  • нужно использовать HttpClient.Current в ASP.net

В этих случаях не следует использовать ConfigureAwait(false) как важно захватить текущий контекст, в противном случае приложение вылетит при попытке получить доступ к представлениям пользовательского интерфейса из потока, не являющегося пользовательским интерфейсом.

Когда пишешь, await task; , что эквивалентно написанию await task.ConfigureAwait(true); , Так что по умолчанию это правда.

Ответ 3

Если ConfigureAwait инициализируется false, код не будет работать в основном потоке (поток пользовательского интерфейса), но если он true, то он будет.

Я рекомендую вам чаще использовать SyncContext.