c# 异步方法不起作用
c# 异步方法不起作用
考虑以下使用vs 2015编写的控制台应用程序的代码:
using System; using System.Threading.Tasks; public class Example { public static void Main() { Console.WriteLine("请稍等...."); DateTime time1 = DateTime.Now; Task task1 = MyAsyncFun1(); Task task2 = MyAsyncFun2(); task1.Wait(); task2.Wait(); DateTime time2 = DateTime.Now; Console.WriteLine("耗时: " + (time2 - time1).TotalSeconds); Console.ReadLine(); } private static async Task MyAsyncFun1() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } private static async Task MyAsyncFun2() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } }
这里有两个异步调用的方法,所有都正常工作,因为执行是并行的,所以“耗时”没有超过2秒。
但是当我将这段代码写在一个ApiController的Action方法中,像这样:
public class MyController : ApiController { private static async Task MyAsyncFun1() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } private static async Task MyAsyncFun2() { await Task.Yield(); System.Threading.Thread.Sleep(2000); } public async TaskMyAction([FromBody] Mymodel model) { DateTime time1 = DateTime.Now; Task task1 = MyAsyncFun1(); Task task2 = MyAsyncFun2(); task1.Wait(); task2.Wait(); DateTime time2 = DateTime.Now; double d=(time2 - time1).TotalSeconds; return .....; } }
执行在task1.Wait()语句上无限期地挂起。
C#异步方法不起作用的原因可能是因为您的代码运行在ASP.NET(而不是ASP.NET Core)中,并且有一个需要独占访问的SynchronizationContext,当您在异步代码上阻塞时,会出现死锁的风险,就像您在这里做的一样。
这里发生的情况是,按时间顺序,您的第一个awaited未完成任务在MyAsyncFun1内发生,等待Task.Yield(),这将立即返回一个未完成的任务,并在稍后将继续(sleep)返回到当前SynchronizationContext。
稍后,您在task1上调用.Wait(),它将阻塞直到完成,但它需要SynchronizationContext可用,但您正在使用它的等待阻塞线程,所以陷入了僵局,死锁。
您可以在等待的任务上使用.ConfigureAwait(false),以确保它们不需要将继续返回到当前的SynchronizationContext,但更好的做法当然是到处都使用await,并且从上到下使用异步。