考虑以下内容(基于默认的MVC模板),它是后台发生的某些“填充”的简化版本-可以很好地完成并显示预期结果20:
public ActionResult Index()
{
var task = SlowDouble(10);
string result;
if (task.Wait(2000))
{
result = task.Result.ToString();
}
else
{
result = "timeout";
}
ViewBag.Message = result;
return View();
}
internal static Task<long> SlowDouble(long val)
{
TaskCompletionSource<long> result = new TaskCompletionSource<long>();
ThreadPool.QueueUserWorkItem(delegate
{
Thread.Sleep(50);
result.SetResult(val * 2);
});
return result.Task;
}
但是,现在,如果我们在混合中添加一些
async
:public static async Task<long> IndirectSlowDouble(long val)
{
long result = await SlowDouble(val);
return result;
}
并将路线的第一行更改为:
var task = IndirectSlowDouble(10);
然后不起作用;它超时了。如果我们添加断点,则
return result;
方法中的async
仅在路由完成之后才会发生-基本上,看来系统不愿意使用任何线程来继续async
操作,直到请求完成为止。更糟糕的是:如果我们使用了.Wait()
(或访问了.Result
),那么它将完全死锁。那么:那是什么?明显的解决方法是“不涉及
async
”,但这在使用库等时并不容易。最终,SlowDouble
和IndirectSlowDouble
之间没有功能上的差异(尽管存在明显的结构差异)。注意:在console / winform / etc中完全一样的东西可以正常工作。
最佳答案
这与在ASP.NET(.NET 4.5之前)中实现同步上下文的方式有关。关于此行为有很多问题:
Task.WaitAll hanging with multiple awaitable tasks in ASP.NET
Asp.net SynchronizationContext locks HttpApplication for async continuations?
在ASP.NET 4.5中,本文介绍了同步上下文的新实现。
http://blogs.msdn.com/b/webdev/archive/2012/11/19/all-about-httpruntime-targetframework.aspx
关于asp.net - 在MVC路由中使用 “async”(即使应该完成)也会使路由死锁;如何避免这种情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13621647/