调用EF异步方法时异步任务冻结

时间:2015-06-25 07:48:28

标签: c# entity-framework asynchronous

我有一个返回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异步方法。有没有理由说它会挂起来?

1 个答案:

答案 0 :(得分:2)

如果您的代码阻止异步代码,则为subject to a deadlock situation。我在博客上完整地描述了这一点,但一般的要点是:

  • await产生调用线程时,默认情况下它首先捕获“上下文”。这通常是UI上下文(对于UI应用程序),ASP.NET请求上下文(对于服务器应用程序)或线程池上下文。
  • 当等待操作完成时,async状态机通过将安排到该上下文来恢复执行。因此,UI线程上的async方法将在该UI线程上恢复,处理ASP.NET请求的async方法将继续处理相同的ASP.NET请求。
  • 某些上下文(例如,UI上下文和ASP.NET请求上下文)一次只允许一个线程。因此,如果在该上下文中存在阻塞的线程,则async方法将在恢复之前等待该线程。在这种情况下,线程被阻塞,等待async方法完成,这是因为它等待被阻塞的线程所以无法完成。经典僵局。

您可能还会发现我的async intro帖子很有帮助。最后,我列出了“旧的阻塞做事方式”(应该避免)以及“新的异步做事方式”。本案例中的相关示例是将Task.WaitAll替换为await Task.WhenAll