Recherche…


Pseudocode pour asynchrone / en attente de mots-clés

Considérons une méthode asynchrone simple:

async Task Foo()
{
    Bar();
    await Baz();
    Qux();
}

En simplifiant, on peut dire que ce code signifie en réalité ce qui suit:

Task Foo()
{
    Bar();
    Task t = Baz();
    var context = SynchronizationContext.Current;
    t.ContinueWith(task) =>
    {
        if (context == null)
            Qux();
        else
            context.Post((obj) => Qux(), null);
    }, TaskScheduler.Current);

    return t;
}

Cela signifie que les mots-clés async / d' await utilisent le contexte de synchronisation actuel s'il existe. C'est-à-dire que vous pouvez écrire du code de bibliothèque qui fonctionnerait correctement dans les applications d'interface utilisateur, Web et console.

Article source

Désactivation du contexte de synchronisation

Pour désactiver le contexte de synchronisation, vous devez appeler la méthode ConfigureAwait :

async Task() Foo()
{
    await Task.Run(() => Console.WriteLine("Test"));
}

. . .

Foo().ConfigureAwait(false);

ConfigureAwait fournit un moyen d'éviter le comportement de capture par défaut de SynchronizationContext; Le fait de transmettre false pour le paramètre flowContext empêche le SynchronizationContext d'être utilisé pour reprendre l'exécution après l'attente.

Citation de It's All About le SynchronizationContext .

Pourquoi SynchronizationContext est-il si important?

Considérez cet exemple:

private void button1_Click(object sender, EventArgs e)
{
    label1.Text = RunTooLong();
}

Cette méthode gèle l'application de l'interface utilisateur jusqu'à ce que RunTooLong soit terminé. L'application ne répondra plus.

Vous pouvez essayer d'exécuter le code interne de manière asynchrone:

private void button1_Click(object sender, EventArgs e)
{
    Task.Run(() => label1.Text = RunTooLong());
}

Mais ce code ne s'exécutera pas car le corps interne peut être exécuté sur un thread non-interface utilisateur et il ne devrait pas modifier directement les propriétés de l'interface utilisateur :

private void button1_Click(object sender, EventArgs e)
{
    Task.Run(() =>
    {
        var label1Text = RunTooLong();

        if (label1.InvokeRequired)
            lable1.BeginInvoke((Action) delegate() { label1.Text = label1Text; });
        else
            label1.Text = label1Text;
    });
}

Maintenant, n'oubliez pas de toujours utiliser ce modèle. Ou, essayez SynchronizationContext.Post qui le fera pour vous:

private void button1_Click(object sender, EventArgs e)
{
    Task.Run(() =>
    {
        var label1Text = RunTooLong();
        SynchronizationContext.Current.Post((obj) =>
        {
            label1.Text = label1    Text);
        }, null);
    });
}


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow