Я не совсем понимаю разницу между 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()
что достаточно хорошо.