问题
首先,在ASP.NET MVC 环境下对async返回的Task执行Wait()会导致线程死锁。例:
public ActionResult Asv2() { //dead lock var task = AssignValue2(); task.Wait(); return Content(_container); } private void Assign() { _container = "Hello World"; } public async Task AssignValue2() { await Task.Delay(500); await Task.Run(() => Assign()); }
这是由于async方法注册的回调要求返回到调用async的线程——而在主线程(action方法所在线程)中又对Task执行了Wait(),相互等待,导致了死锁。
Wait一个async方法是否一定导致死锁(ASP.NET MVC)
否。Task类型的对象有一个ConfigureAwait方法,将参数置为false可以防止回调返回当前线程。但是有一个前提条件:async方法的调用链中的所有async方法都必须指定ConfigureAwait(false)。例:
public async Task AssignValue2() { await Task.Delay(500); await Task.Run(() => Assign()); } public async Task AssignValue() { await Task.Run(() => Assign()).ConfigureAwait(false); } public async Task Wrapped() { await AssignValue().ConfigureAwait(false); } public async Task Wrapped2() { await AssignValue2().ConfigureAwait(false); } public async Task Update() { await Task.Run(() => { _container = _container + "Hello "; }); } public async Task Update2() { await Task.Run(() => { _container = _container + "World"; }); } #region 基本调用 /// <summary> /// 调用层次最深的异步方法(第一个调用的异步方法)不要求返回到主线程 /// </summary> /// <returns></returns> public ActionResult Asv1() { var task = AssignValue(); task.Wait(); return Content(_container); } /// <summary> /// ...返回主线程 /// </summary> /// <returns></returns> public ActionResult Asv2() { //dead lock var task = AssignValue2(); task.Wait(); return Content(_container); } /// <summary> /// 所有都不要求返回主线程 /// </summary> /// <returns></returns> public ActionResult Wrp() { var task = Wrapped(); task.Wait(); return Content(_container); } /// <summary> /// 其中一个要求返回主线程 /// </summary> /// <returns></returns> public ActionResult Wrp2() { //dead lock var task = Wrapped2(); task.Wait(); return Content(_container); } #endregion