c#中的async方法不是异步的

本文关键字:异步 方法 中的 async | 更新日期: 2023-09-27 18:02:46

创建了以下控制台应用程序后,我有点困惑为什么它似乎是同步运行而不是异步运行:

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        var total = CreateMultipleTasks();
        stopwatch.Stop();
        Console.WriteLine("Total jobs done: {0} ms", total.Result);
        Console.WriteLine("Jobs done in: {0} ms", stopwatch.ElapsedMilliseconds);
    }
    static async Task<int> CreateMultipleTasks()
    {
        var task1 = WaitForMeAsync(5000);
        var task2 = WaitForMeAsync(3000);
        var task3 = WaitForMeAsync(4000);
        var val1 = await task1;
        var val2 = await task2;
        var val3 = await task3;
        return val1 + val2 + val3;
    }
    static Task<int> WaitForMeAsync(int ms)
    {
        Thread.Sleep(ms);
        return Task.FromResult(ms);
    }
}

运行应用程序时,输出为:

已完成的总作业:12000 ms
完成任务时间:12003毫秒

我希望是这样的:

已完成的总作业:12000 ms
任务完成时间:5003 ms

这是因为当我使用线程。Sleep方法,它会停止整个应用程序的进一步执行?还是我遗漏了什么重要的东西?

c#中的async方法不是异步的

即使您转换为使用Task.RunTask.Delay作为其他答案建议,您应该避免在async方法中的任何地方使用阻塞Task.WaitAll,尽可能多。混合异步和同步代码通常不是一个好主意,它会增加冗余阻塞线程的数量,并导致死锁。

相反,使用await Task.WhenAll并将阻塞等待移动到顶层(即在本例中使用Main方法):

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        var total = CreateMultipleTasks();
        total.Wait();
        stopwatch.Stop();
        Console.WriteLine("Total jobs done: {0} ms", total.Result);
        Console.WriteLine("Jobs done in: {0} ms", stopwatch.ElapsedMilliseconds);
    }
    static async Task<int> CreateMultipleTasks()
    {
        var task1 = Task.Run(() => WaitForMeAsync(5000));
        var task2 = Task.Run(() => WaitForMeAsync(3000));
        var task3 = Task.Run(() => WaitForMeAsync(4000));
        await Task.WhenAll(new Task[] { task1, task2, task3 });
        return task1.Result + task2.Result + task3.Result;
    }
    static int WaitForMeAsync(int ms)
    {
        // assume Thread.Sleep is a placeholder for a CPU-bound work item
        Thread.Sleep(ms);
        return ms;
    }
}

附带说明,查看Stephen Toub的"我应该为同步方法公开异步包装器吗?"answers"我应该为同步方法公开异步包装器吗?"

以同步方式运行任务。你可以这样做:

static async Task<int> CreateMultipleTasks()
{
    var task1 = Task.Run<int>(() => WaitForMeAsync(5000));
    var task2 = Task.Run<int>(() => WaitForMeAsync(3000));
    var task3 = Task.Run<int>(() => WaitForMeAsync(4000));
    Task.WaitAll(new Task[] { task1, task2, task3 });
    return task1.Result + task2.Result + taks3.Result;
}

在一行中使用三个await将不会并行运行任务。它将释放线程,而它正在等待(如果你使用await Task.Delay(ms)作为Thread.Sleep(ms)是一个阻塞操作),但当前的执行将不会继续与task2,而task1是"睡眠"。

你的WaitForMeAsync方法只是一个假装为异步的简单同步方法。

你不执行任何异步操作,Sleep()只是阻塞线程。

为什么要延迟异步?(是的,你可以使用await Task.Delay(ms)),需要更多的输入来帮助那里。