简体   繁体   English

C#中的异步方法不是异步的吗?

[英]async method in C# not asynchronous?

Having created the following console application I am a little puzzled why it seems to run synchronously instead of asynchronously: 创建了以下控制台应用程序后,我有点困惑为什么它似乎同步运行而不是异步运行:

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);
    }
}

When running the application, output is: 运行应用程序时,输出为:

Total jobs done: 12000 ms 完成的工作总数:12000毫秒
Jobs done in: 12003 ms 工作完成时间:12003毫秒

I would have expected somehing like: 我原以为是会像以下一样:

Total jobs done: 12000 ms 完成的工作总数:12000毫秒
Jobs done in: 5003 ms 工作完成时间:5003毫秒

Is this because when I use the Thread.Sleep method it stops further execution of the whole application? 这是因为当我使用Thread.Sleep方法时它会停止进一步执行整个应用程序吗? Or am I missing something important here? 或者我错过了一些重要的东西?

Even when you convert to using Task.Run or Task.Delay as other answers suggest, you should avoid using the blocking Task.WaitAll anywhere inside async methods , as much as you can. 即使你转换为使用Task.RunTask.Delay作为其他答案建议, 你应该尽可能避免在async方法中的任何地方使用阻塞Task.WaitAll Mixing asynchronous and synchronous code is usually a bad idea, it increases the number of redundantly blocked threads and promotes deadlocks. 混合异步和同步代码通常是一个坏主意,它会增加冗余阻塞线程的数量并促进死锁。

Instead, use await Task.WhenAll and move the blocking wait to the top level (ie, Main method in this case): 相反,使用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;
    }
}

On a side note, check Stephen Toub's "Should I expose asynchronous wrappers for synchronous methods?" 另外,请查看Stephen Toub的“我应该为同步方法公开异步包装器吗?” and "Should I expose asynchronous wrappers for synchronous methods?" “我应该为同步方法公开异步包装器吗?”

Your WaitForMeAsync method is just a simple sync method pretending to be an async one. 您的WaitForMeAsync方法只是一个假装为异步的简单同步方法。

You don't perform anything async and Sleep() just blocks the thread. 你不执行任何异步,Sleep()只是阻塞线程。

Why would you want to delay async? 为什么要延迟异步? (yes you can use await Task.Delay(ms) ), need more input to help there. (是的,你可以使用await Task.Delay(ms) ),需要更多的输入来帮助那里。

You run the task in a synchounus manner. 您以同步方式运行任务。 You can do something like this: 你可以这样做:

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;

}

Using the three await in a row will NOT run the tasks in parallel. 连续使用三个await将不会并行运行任务。 It will just free the thread while it is waiting (if you use await Task.Delay(ms) as Thread.Sleep(ms) is a blocking operation), but the current execution will NOT continue with task2 while task1 is "sleeping". 它只是将释放线程在等待时(如果你使用await Task.Delay(ms)Thread.Sleep(ms)是一种阻塞操作),但目前的执行将不继续task2task1是“睡觉”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM