Buscar..


Pseudocódigo para palabras clave async / await

Considere un método asíncrono simple:

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

Simplificando, podemos decir que este código en realidad significa lo siguiente:

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 que las palabras clave async / await usan el contexto de sincronización actual si existe. Es decir, puede escribir un código de biblioteca que funcione correctamente en las aplicaciones de UI, Web y Consola.

Artículo fuente .

Deshabilitando el contexto de sincronización

Para deshabilitar el contexto de sincronización, debe llamar al método ConfigureAwait :

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

. . .

Foo().ConfigureAwait(false);

ConfigureAwait proporciona un medio para evitar el comportamiento de captura predeterminado de SynchronizationContext; pasar falso para el parámetro flowContext evita que se use SynchronizationContext para reanudar la ejecución después de la espera.

Cita de Todo se trata del SynchronizationContext .

¿Por qué SynchronizationContext es tan importante?

Considera este ejemplo:

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

Este método congelará la aplicación de la interfaz de usuario hasta que se complete el RunTooLong . La aplicación no responderá.

Puede intentar ejecutar código interno de forma asíncrona:

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

Pero este código no se ejecutará porque el cuerpo interno puede ejecutarse en un subproceso que no pertenece a la IU y no debería cambiar las propiedades de la IU directamente :

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

Ahora no olvides usar siempre este patrón. O intente SynchronizationContext.Post que lo hará por usted:

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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow