Je ne comprends pas très bien la différence entre Task.Waitet await.
J'ai quelque chose de similaire aux fonctions suivantes dans un service 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
}
}
Où Getsera l'impasse.
Qu'est-ce qui pourrait provoquer cela? Pourquoi cela ne pose-t-il pas un problème lorsque j'utilise une attente de blocage plutôt que await Task.Delay?
Task.Delay(1).Wait()est fondamentalement la même chose que Thread.Sleep(1000). Dans le code de production réel, il est rarement approprié.
WaitAllest à l'origine de l'impasse. Voir le lien vers mon blog dans ma réponse pour plus de détails. Vous devez utiliser à la await Task.WhenAllplace.
ConfigureAwait(false)un seul appel àBarRos impasse ou ne la bloquerez pas, mais parce que vous avez un énumérable qui en crée plus d'une et attend ensuite toutes, la première barre bloquera la seconde. Si vous await Task.WhenAllau lieu d'attendre toutes les tâches, afin de ne pas bloquer le contexte ASP, vous verrez la méthode retourner normalement.
.ConfigureAwait(false) tout le long de l'arborescence jusqu'à ce que vous bloquiez, de cette façon, rien n'essaye jamais de revenir au contexte principal; Ça marcherait. Une autre option serait de faire tourner un contexte de synchronisation interne. Lien . Si vous mettez le Task.WhenAlldans un, AsyncPump.Runil bloquera efficacement le tout sans que vous ayez besoin de ConfigureAwaitquelque part, mais c'est probablement une solution trop complexe.
Task.Delay(1).Wait()ce qui est assez bon.