No entiendo la diferencia entre Task.Wait
y await
.
Tengo algo similar a las siguientes funciones en un servicio ASP.NET WebAPI:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
¿Dónde Get
quedará estancado?
Que podria causar esto? ¿Por qué esto no causa un problema cuando uso una espera de bloqueo en lugar de hacerlo await Task.Delay
?
Task.Delay(1).Wait()
es básicamente exactamente lo mismo que Thread.Sleep(1000)
. En el código de producción real rara vez es apropiado.
WaitAll
está causando el punto muerto. Vea el enlace a mi blog en mi respuesta para más detalles. Deberías usar await Task.WhenAll
en su lugar.
ConfigureAwait(false)
una sola llamada a un punto muerto Bar
o Ros
no lo hará, pero debido a que tiene un número enumerable que está creando más de uno y luego espera a todos, la primera barra bloqueará el segundo. Si en await Task.WhenAll
lugar de esperar todas las tareas, para no bloquear el contexto ASP, verá que el método regresa normalmente.
.ConfigureAwait(false)
todo el camino hasta el árbol hasta que se bloquea, de esa manera nada está siempre tratando de volver al contexto principal; eso funcionaria. Otra opción sería activar un contexto de sincronización interna. Enlace . Si lo coloca Task.WhenAll
dentro AsyncPump.Run
, bloqueará efectivamente todo el proceso sin que lo necesite en ConfigureAwait
ningún lado, pero esa es probablemente una solución demasiado compleja.
Task.Delay(1).Wait()
que es lo suficientemente bueno.