Não entendo bem a diferença entre Task.Waite await.
Eu tenho algo semelhante às seguintes funções em um serviço 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
}
}
Onde Getserá um impasse.
O que poderia causar isso? Por que isso não causa um problema quando eu uso uma espera de bloqueio em vez de await Task.Delay?
Task.Delay(1).Wait()é basicamente a mesma coisa que Thread.Sleep(1000). No código de produção real, raramente é apropriado.
WaitAllestá causando o impasse. Veja o link para o meu blog na minha resposta para mais detalhes. Você deve usar em seu await Task.WhenAlllugar.
ConfigureAwait(false)uma chamada únicaBar ou Rosnão entra em conflito, mas porque possui um enumerável que está criando mais de uma e aguardando todas, a primeira barra entra em impasse na segunda. Se você, em await Task.WhenAllvez de esperar em todas as tarefas, para não bloquear o contexto ASP, verá o método retornar normalmente.
.ConfigureAwait(false) todo o caminho até a árvore até que você bloquear, dessa forma nada está sempre tentando voltar para o contexto principal; Isso funcionaria. Outra opção seria ativar um contexto de sincronização interno. Link . Se você colocar o item Task.WhenAllem, AsyncPump.Runele efetivamente bloqueará a coisa toda sem a necessidade de ir a ConfigureAwaitqualquer lugar, mas provavelmente é uma solução excessivamente complexa.
Task.Delay(1).Wait()que é bom o suficiente.