Szukaj…


Pseudokod dla słów kluczowych async / czekaj

Rozważ prostą metodę asynchroniczną:

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

Upraszczając, możemy powiedzieć, że ten kod w rzeczywistości oznacza:

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

Oznacza to, że słowa kluczowe async / await wykorzystują bieżący kontekst synchronizacji, jeśli istnieje. Można np. Napisać kod biblioteki, który działałby poprawnie w aplikacjach UI, Web i Console.

Artykuł źródłowy .

Wyłączanie kontekstu synchronizacji

Aby wyłączyć kontekst synchronizacji, należy wywołać metodę ConfigureAwait :

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

. . .

Foo().ConfigureAwait(false);

ConfigureAwait zapewnia sposób na uniknięcie domyślnego zachowania przechwytywania SynchronizationContext; przekazanie wartości false dla parametru flowContext uniemożliwia użycie SynchronizationContext do wznowienia wykonywania po oczekiwaniu.

Cytat z „Wszystko o kontekście synchronizacji” .

Dlaczego SynchronizationContext jest tak ważny?

Rozważ ten przykład:

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

Ta metoda spowoduje zawieszenie aplikacji interfejsu użytkownika do czasu zakończenia RunTooLong . Aplikacja nie będzie odpowiadać.

Możesz spróbować uruchomić wewnętrzny kod asynchronicznie:

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

Ale ten kod nie zostanie wykonany, ponieważ wewnętrzna treść może być uruchamiana w wątku innym niż interfejs użytkownika i nie powinna bezpośrednio zmieniać właściwości interfejsu :

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

Teraz nie zapomnij zawsze używać tego wzoru. Lub spróbuj SynchronizationContext.Post , który zrobi to za Ciebie:

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow