Ricerca…


Pseudocodice per parole chiave asincrone / attese

Considera un semplice metodo asincrono:

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

Semplificando, possiamo dire che questo codice in realtà significa quanto segue:

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

Significa che le parole chiave async / await il contesto di sincronizzazione corrente se esiste. Ad esempio, è possibile scrivere codice di libreria che funzioni correttamente in applicazioni UI, Web e Console.

Articolo di origine

Disabilitare il contesto di sincronizzazione

Per disabilitare il contesto di sincronizzazione, devi chiamare il metodo ConfigureAwait :

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

. . .

Foo().ConfigureAwait(false);

ConfigureAwait fornisce un mezzo per evitare il comportamento di cattura predefinito di SynchronizationContext; il passaggio di false per il parametro flowContext impedisce l'utilizzo di SynchronizationContext per riprendere l'esecuzione dopo l'attesa.

Citazione tratta da It's All About the SynchronizationContext .

Perché SynchronizationContext è così importante?

Considera questo esempio:

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

Questo metodo bloccherà l'applicazione dell'interfaccia utente fino al completamento di RunTooLong . L'applicazione non risponderà.

Puoi provare a eseguire il codice interno in modo asincrono:

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

Ma questo codice non verrà eseguito perché il corpo interno può essere eseguito su thread non UI e non dovrebbe modificare direttamente le proprietà dell'interfaccia utente :

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

Ora non dimenticare di usare sempre questo modello. Oppure prova SynchronizationContext.Post che lo farà per te:

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow