Suche…


Pseudocode für async / await-Schlüsselwörter

Betrachten Sie eine einfache asynchrone Methode:

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

Vereinfachend können wir sagen, dass dieser Code eigentlich Folgendes bedeutet:

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

Das bedeutet, dass async / await Schlüsselwörter den aktuellen Synchronisationskontext verwenden, sofern vorhanden. Sie können also Bibliothekscode schreiben, der in UI-, Web- und Konsolenanwendungen ordnungsgemäß funktionieren würde.

Quellartikel .

Synchronisierungskontext deaktivieren

Um den Synchronisationskontext zu deaktivieren, rufen Sie die ConfigureAwait Methode auf:

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

. . .

Foo().ConfigureAwait(false);

Mit ConfigureAwait können Sie das standardmäßige Aufnahmeverhalten von SynchronizationContext vermeiden. Durch das Übergeben von false für den Parameter flowContext wird verhindert, dass SynchronizationContext verwendet wird, um die Ausführung nach dem Erwarten wieder aufzunehmen.

Zitat von Es ist alles über den SynchronizationContext .

Warum ist SynchronizationContext so wichtig?

Betrachten Sie dieses Beispiel:

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

Diese Methode friert die UI-Anwendung ein, bis RunTooLong abgeschlossen ist. Die Anwendung reagiert nicht.

Sie können versuchen, den inneren Code asynchron auszuführen:

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

Dieser Code wird jedoch nicht ausgeführt, da der innere Körper möglicherweise auf einem Thread außerhalb der Benutzeroberfläche ausgeführt wird und die Eigenschaften der Benutzeroberfläche nicht direkt geändert werden sollten :

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;
    });
}

Vergessen Sie nicht, immer dieses Muster zu verwenden. Oder versuchen Sie es mit SynchronizationContext.Post , das es für Sie machen wird:

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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow