考虑以下(基于默认模板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
(虽然有明显的结构性差异)。
注:在控制台/ WinForm的同样的事情在/ etc将正常工作。