我不太明白Task和Task的区别。等啊等。
我有类似于以下功能在一个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时,这不会引起问题?
等待和等待——虽然概念相似——实际上完全不同。
Wait将同步阻塞直到任务完成。因此,当前线程被阻塞,等待任务完成。一般来说,你应该自始至终使用“async”;也就是说,不要阻塞异步代码。在我的博客上,我详细介绍了异步代码中的阻塞是如何导致死锁的。
Await将异步等待直到任务完成。这意味着当前方法处于“暂停”状态(它的状态被捕获),并且该方法将未完成的任务返回给调用者。之后,当await表达式完成时,该方法的其余部分被调度为一个延续。
你还提到了“协作块”,我想你的意思是你正在等待的任务可能会在等待线程上执行。有些情况下会发生这种情况,但这是一种优化。在许多情况下,它不会发生,比如任务是另一个调度器的任务,或者它已经启动,或者它是非代码任务(例如在您的代码示例中:Wait不能内联执行Delay任务,因为没有用于它的代码)。
你可能会发现我的async / await介绍很有用。
一些重要的事实在其他答案中没有给出:
async/await在CIL级别上更复杂,因此会消耗内存和CPU时间。
如果等待时间不可接受,任何任务都可以取消。
在async/await的情况下,我们没有这样一个任务的处理程序来取消它或监视它。
使用Task比async/await更灵活。
任何同步功能都可以通过async封装。
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
Async /await会产生很多问题。我们不知道在没有运行时和上下文调试的情况下是否会到达await语句。如果第一个等待没有到达,一切都被阻塞。有时候,等待似乎到了,但一切仍然受阻:
https://github.com/dotnet/runtime/issues/36063
我不明白为什么我必须生活在代码复制同步和异步方法或使用黑客。
结论:手动创建任务并控制它们要好得多。Handler to Task提供了更多的控制。我们可以监视任务并管理它们:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
对不起,我的英语不好。