c# 异步方法不起作用

8 浏览
0 Comments

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 Task MyAction([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()语句上无限期地挂起。

0
0 Comments

C#异步方法不起作用的原因可能是因为您的代码运行在ASP.NET(而不是ASP.NET Core)中,并且有一个需要独占访问的SynchronizationContext,当您在异步代码上阻塞时,会出现死锁的风险,就像您在这里做的一样。

这里发生的情况是,按时间顺序,您的第一个awaited未完成任务在MyAsyncFun1内发生,等待Task.Yield(),这将立即返回一个未完成的任务,并在稍后将继续(sleep)返回到当前SynchronizationContext。

稍后,您在task1上调用.Wait(),它将阻塞直到完成,但它需要SynchronizationContext可用,但您正在使用它的等待阻塞线程,所以陷入了僵局,死锁。

您可以在等待的任务上使用.ConfigureAwait(false),以确保它们不需要将继续返回到当前的SynchronizationContext,但更好的做法当然是到处都使用await,并且从上到下使用异步。

0