我不太明白之间的差别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)
在树上一直添加直到被阻止为止,这样就不会尝试返回主上下文了。那会起作用。另一个选择是启动内部同步上下文。 链接。如果您将它放进去Task.WhenAll
,AsyncPump.Run
它将有效地阻塞整个事情,而无需到ConfigureAwait
任何地方,但这可能是一个过于复杂的解决方案。
Task.Delay(1).Wait()
。