without method await async c# async-await synchronizationcontext

c# - method - ¿Por qué me molestaría en usar Task.ConfigureAwait(continueOnCapturedContext: false);



call async method c# await (2)

Considere el siguiente código de formularios de 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."; }

Aquí la excepción se produce en la tercera línea porque después de esperar, el código se ejecuta en un subproceso que no es UI. ¿Dónde es útil ConfigureAwait (false)?


Debe usarlo en todo momento en los servicios, ya que los servicios deben ser independientes de la interfaz de usuario.

Sin embargo, no lo use fuera de los servicios si

  • necesita manipular la interfaz de usuario o usar componentes específicos de la interfaz de usuario, como Dispatcher o CoreDispatcher
  • necesita usar HttpClient.Current en ASP.net

En estos casos, no debe usar ConfigureAwait(false) ya que es importante capturar el contexto actual; de lo contrario, la aplicación se bloqueará al intentar acceder a las vistas de la interfaz de usuario desde un hilo que no sea de la interfaz de usuario

Cuando escribes await task; , eso es equivalente a la task.ConfigureAwait(true); escritura en espera. task.ConfigureAwait(true); . Tan cierto es el valor predeterminado.


Stephen Cleary tiene una serie realmente buena sobre esto que puede encontrar aquí , cité la pieza específica para su pregunta:

La mayoría de las veces, no necesita volver a sincronizar con el contexto "principal". La mayoría de los métodos asíncronos se diseñarán teniendo en cuenta la composición: esperan otras operaciones, y cada uno representa una operación asincrónica en sí misma (que puede estar compuesta por otros). En este caso, desea decirle al camarero que no capture el contexto actual llamando a ConfigureAwait y pasando false , por ejemplo:

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!"; }

Lo importante a tener en cuenta con este ejemplo es que cada "nivel" de llamadas a métodos asíncronos tiene su propio contexto. DownloadFileButton_Click comenzó en el contexto de la interfaz de usuario y se llamó DownloadFileAsync . DownloadFileAsync también comenzó en el contexto de la interfaz de usuario, pero luego salió de su contexto llamando a ConfigureAwait(false) . El resto de DownloadFileAsync ejecuta en el contexto del grupo de subprocesos. Sin embargo, cuando DownloadFileAsync completa y DownloadFileButton _Click se reanuda, se reanuda en el contexto de la interfaz de usuario.

Una buena regla general es usar ConfigureAwait(false) menos que sepa que necesita el contexto.