web-dev-qa-db-fra.com

Pourquoi prendrais-je la peine d'utiliser Task.ConfigureAwait (continueOnCapturedContext: false);

Considérez le code suivant des formulaires 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.";
    }

Ici, l'exception est levée à la 3ème ligne car après attendre, le code est exécuté sur un thread non-UI. Où ConfigureAwait (false) est utile?

55
Yawar Murtaza

Stephen Cleary a une très bonne série sur ce que vous pouvez trouver ici , j'ai cité le morceau spécifique à votre question:

La plupart du temps, vous n’avez pas besoin pour vous synchroniser avec le contexte "principal". La plupart des méthodes asynchrones seront conçues avec une composition en tête: elles attendent d’autres opérations, et chacune d’elles représente une opération asynchrone elle-même (qui peut être composée par d’autres). Dans ce cas, vous voulez dire à l'attente pas capturer le contexte actuel en appelant ConfigureAwait et en passant false, par exemple:

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

La chose importante à noter avec cet exemple est que chaque "niveau" d'appels de méthode async a son propre contexte. DownloadFileButton_Click A démarré dans le contexte de l'interface utilisateur et appelé DownloadFileAsync. DownloadFileAsync a également commencé dans le contexte de l'interface utilisateur, mais est sorti de son contexte en appelant ConfigureAwait(false). Le reste de DownloadFileAsync s'exécute dans le contexte du pool de threads. Cependant, lorsque DownloadFileAsync est terminé et que DownloadFileButton_ Click reprend, il fait reprend dans le contexte de l'interface utilisateur.

Une bonne règle est d'utiliser ConfigureAwait(false) à moins que vous ne vous connaissiez faites avez besoin du contexte.

79
Victor Learned

Vous devez l’utiliser à tout moment dans les services, car ceux-ci doivent être agnostiques à l’interface utilisateur.

Cependant, ne l'utilisez pas en dehors des services si

  • besoin de manipuler l'interface utilisateur ou d'utiliser des composants spécifiques à l'interface utilisateur tels que Dispatcher ou CoreDispatcher
  • besoin d'utiliser HttpClient.Current dans ASP.net

Dans ces cas, vous ne devez pas utiliser ConfigureAwait(false) car il est important de capturer le contexte actuel, sinon l'application plantera en essayant d'accéder aux vues d'interface utilisateur à partir d'un thread non-UI.

Lorsque vous écrivez await task;, Cela équivaut à écrire wait task.ConfigureAwait(true);. Si vrai est le défaut.

1
pixel