C# 等待vs任务。等待-死锁?
我不太明白C# 等待vs任务。等待-死锁?,c#,task-parallel-library,deadlock,async-await,C#,Task Parallel Library,Deadlock,Async Await,我不太明白Task.Wait和Wait之间的区别 我在ASP.NET WebAPI服务中具有类似于以下函数的功能: public class TestController : ApiController { public static async Task<string> Foo() { await Task.Delay(1).ConfigureAwait(false); return ""; } public asy
Task.Wait
和Wait
之间的区别
我在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
}
}
公共类TestController:ApiController
{
公共静态异步任务Foo()
{
等待任务。延迟(1)。配置等待(false);
返回“”;
}
公共异步静态任务栏()
{
返回等待Foo();
}
公共异步静态任务Ros()
{
返回等待条();
}
//获取api/测试
公共IEnumerable Get()
{
Task.WaitAll(Enumerable.Range(0,10).Select(x=>Ros()).ToArray());
返回新字符串[]{“value1”,“value2”};//这将永远不会执行
}
}
其中Get
将死锁
这是什么原因造成的?当我使用阻塞等待而不是
等待任务时,为什么这不会导致问题。延迟
?等待
和等待
虽然在概念上相似,但实际上完全不同
Wait
将同步阻止,直到任务完成。因此,当前线程实际上被阻塞,等待任务完成。一般来说,您应该一直使用“async
”;也就是说,不要阻塞async
code。在我的博客上,我详细介绍了我的工作
wait
将异步等待,直到任务完成。这意味着当前方法已“暂停”(其状态已捕获),并且该方法将不完整的任务返回给调用方。稍后,当await
表达式完成时,该方法的剩余部分将被安排为继续
您还提到了一个“协作块”,我假设您的意思是您正在等待的任务可能会在等待线程上执行。有些情况下可能会发生这种情况,但这是一种优化。在许多情况下,它都不会发生,例如任务是为另一个计划程序执行的,或者它已经启动,或者它是一个非代码任务(例如在代码示例中:Wait
无法内联执行Delay
任务,因为它没有代码)
您可能会发现我的建议很有帮助。根据我从不同来源读到的内容: 表达式不会阻止正在其上执行的线程。相反,它会导致编译器将
async
方法的其余部分注册为等待任务的延续。控件然后返回给async
方法的调用方。当任务完成时,它调用它的continuation,并且async
方法的执行在它停止的地方继续
要等待单个任务完成,可以调用其任务.wait
方法。对Wait
方法的调用会阻塞调用线程,直到单个类实例完成执行。无参数的Wait()
方法用于无条件等待任务完成。该任务通过调用线程.Sleep
方法睡眠两秒钟来模拟工作
这也是一本很好的读物。其他答案中没有给出一些重要事实: “异步等待”在CIL级别更为复杂,因此需要占用内存和CPU时间 如果等待时间不可接受,则可以取消任何任务 在“async await”的情况下,我们没有处理此类任务的处理程序来取消它或监视它 使用任务比“异步等待”更灵活 任何同步功能都可以通过async包装
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
公共异步任务
我不明白为什么我必须接受同步和异步方法的代码复制或使用黑客
结论:手工创建任务并进行控制效果更好。处理程序对任务给予更多的控制。我们可以监控和管理任务:
对不起,我的英语不太好。我认为有一个误解,Wait
工作正常Wait
死锁。显然:是的,如果我用Task.Delay(1)
替换我的Wait任务。Delay(1)。Wait()
服务工作正常,否则它会死锁。不,任务调度程序不会这样做Wait
阻塞线程,它不能用于其他事情。@ronag我猜你只是把方法名弄混了,你的死锁实际上是由阻塞代码引起的,并使用了Wait
代码。要么是这样,要么是死锁与之无关,而您错误地诊断了问题。@hexterminator:这是设计的-它对UI应用程序非常有效,但却会妨碍ASP.NET应用程序。ASP.NET Core已通过删除同步上下文解决了此问题,因此ASP.NET Core请求中的阻止不再死锁。@Servy:我会在有时间时立即返回回购。目前,它与Task.Delay(1.Wait()
一起工作,这已经足够好了。Task.Delay(1.Wait()
基本上与Thread.Sleep(1000)
完全相同。在实际的生产代码中,它很少合适。@ronag:YourWaitAll
导致死锁。有关更多详细信息,请参见我回答中的我的博客链接。您应该使用wait Task.whalll
。@ronag因为您有configurewait(false)
对Bar
或Ros
的一次调用不会死锁,但是因为您有一个创建多个然后等待所有这些的可枚举项,所以第一个条将死锁第二个条。如果您等待任务。当所有的不是等待所有的任务,这样您就不会阻塞ASP上下文,您将看到该方法正常返回。@ronag您的另一个选项是在树上一直添加。ConfigureAwait(false)
,直到您阻塞为止,这样就不会有任何东西试图返回主上下文;那就行了。另一种选择是启动内部同步上下文。如果将任务.whalll
放入异步泵中,请运行