espera La Tarea.Delay() frente a la Tarea.Retraso().Esperen()


En C# tengo los siguientes dos ejemplos simples:

[Test]
public void TestWait()
{
    var t = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Start");
        Task.Delay(5000).Wait();
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

[Test]
public void TestAwait()
{
    var t = Task.Factory.StartNew(async () =>
    {
        Console.WriteLine("Start");
        await Task.Delay(5000);
        Console.WriteLine("Done");
    });
    t.Wait();
    Console.WriteLine("All done");
}

El primer ejemplo crea una tarea que imprime "Start", espera 5 segundos imprime "Done" y luego finaliza la tarea. Espero a que termine la tarea y luego imprimo "Todo listo". Cuando hago la prueba hace lo esperado.

La segunda prueba debe tener el mismo comportamiento, excepto que la espera dentro de la Tarea debe ser sin bloqueo debido al uso de async y await. Pero esta prueba solo imprime "Start" y luego inmediatamente " All hecho "y" Hecho " nunca se imprime.

No sé por qué obtengo este comportamiento: Cualquier ayuda sería muy apreciada:)

Author: svenskmand, 2014-11-07

1 answers

La segunda prueba tiene dos tareas anidadas y está esperando la más externa, para arreglar esto debe usar t.Result.Wait(). t.Result obtiene la tarea interna.

El segundo método es aproximadamente equivalente a esto:

public void TestAwait()
{
  var t = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("Start");
                return Task.Factory.StartNew(() =>
                {
                    Task.Delay(5000).Wait(); Console.WriteLine("Done");
                });
            });
            t.Wait();
            Console.WriteLine("All done");
}

Al llamar a t.Wait() está esperando la tarea más externa que regresa inmediatamente.


En última instancia, la forma 'correcta' de manejar este escenario es renunciar a usar Wait en absoluto y simplemente usar await. Wait puede causar problemas de bloqueo una vez que adjuntó una interfaz de usuario a tu código asincrónico.

    [Test]
    public async Task TestCorrect() //note the return type of Task. This is required to get the async test 'waitable' by the framework
    {
        await Task.Factory.StartNew(async () =>
        {
            Console.WriteLine("Start");
            await Task.Delay(5000);
            Console.WriteLine("Done");
        }).Unwrap(); //Note the call to Unwrap. This automatically attempts to find the most Inner `Task` in the return type.
        Console.WriteLine("All done");
    }

Aún mejor simplemente use Task.Run para iniciar su operación asíncrona:

    [TestMethod]
    public async Task TestCorrect()
    {
        await Task.Run(async () => //Task.Run automatically unwraps nested Task types!
        {
            Console.WriteLine("Start");
            await Task.Delay(5000);
            Console.WriteLine("Done");
        });
        Console.WriteLine("All done");
    }
 33
Author: brz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:02:34