Я не зовсім розумію різницю між Task.Waitі await.
У сервісі 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
}
}
Де Getбуде тупик.
Що може спричинити це? Чому це не викликає проблем, коли я використовую блокування очікування, а не await Task.Delay?
Task.Delay(1).Wait()в основному точно те саме, що і Thread.Sleep(1000). У фактичному виробничому коді це рідко доцільно.
WaitAllпричиною стає тупик. Дивіться посилання на мій блог у моїй відповіді для отримання більш детальної інформації. Ви повинні використовувати await Task.WhenAllзамість цього.
ConfigureAwait(false)в єдиний виклик Barабо Rosне безвихідь, а тому , що у вас є перелічуваних , що створює більше , ніж один , а потім чекати на всіх тих, перша смуга буде тупикової другий. Якщо ви await Task.WhenAllзамість того, щоб чекати всіх завдань, щоб не блокувати контекст ASP, ви побачите, як метод повертається нормально.
.ConfigureAwait(false) всю дорогу вгору по дереву, поки ви не заблокуєте, таким чином нічого не намагається повернутися до основного контексту; це спрацювало б. Іншим варіантом було б розкрутити внутрішній контекст синхронізації. Link . Якщо ви помістите Task.WhenAllв нього, AsyncPump.Runвін ефективно блокує всю справу, не потребуючи ConfigureAwaitнікуди, але це, мабуть, надмірно складне рішення.
Task.Delay(1).Wait()чим досить добре.