我有一个返回xml字符串的异步方法。当我将任务添加到任务列表时,它会启动任务,但在使用Entity Framework与数据库通信时会挂起第一个任务。以下是示例代码。
public async Task<ActionResult> GenerateXml(long id)
{
var tasks = new List<Task<string>>();
tasks.Add(GenerateXmlAsync(id));
Task.WaitAll(tasks.ToArray());
}
private async Task<string> GenerateXmlAsync(long id)
{
using (var dbContext = new MyDatabaseContext())
{
var item = await dbContext.Items.FirstOrDefaultAsync(itm => itm.Id = id);
/* do some calculations, generate the xml... */
var xml = "<generated by code above>";
return xml;
}
}
在Azure上使用流日志,我可以看到任务运行但从未使它通过dbContext异步方法。有没有理由说它会挂起来?
答案 0 :(得分:2)
如果您的代码阻止异步代码,则为subject to a deadlock situation。我在博客上完整地描述了这一点,但一般的要点是:
await
产生调用线程时,默认情况下它首先捕获“上下文”。这通常是UI上下文(对于UI应用程序),ASP.NET请求上下文(对于服务器应用程序)或线程池上下文。async
状态机通过将安排到该上下文来恢复执行。因此,UI线程上的async
方法将在该UI线程上恢复,处理ASP.NET请求的async
方法将继续处理相同的ASP.NET请求。async
方法将在恢复之前等待该线程。在这种情况下,线程被阻塞,等待async
方法完成,这是因为它等待被阻塞的线程所以无法完成。经典僵局。您可能还会发现我的async
intro帖子很有帮助。最后,我列出了“旧的阻塞做事方式”(应该避免)以及“新的异步做事方式”。本案例中的相关示例是将Task.WaitAll
替换为await Task.WhenAll
。