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

olf*_*olf 6 c# asynchronous task-parallel-library async-await

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

完成的工作总数:12000 ms
工作完成时间:12003 ms

我原以为是会像以下一样:

完成的工作总数:12000 ms
工作完成时间:5003 ms

这是因为当我使用Thread.Sleep方法时它会停止进一步执行整个应用程序吗?或者我错过了一些重要的东西?

nos*_*tio 5

即使您转换为 usingTask.RunTask.Delay其他答案建议的那样,您也应该避免Task.WaitAll在内部的任何地方使用阻塞asyncmethods。混合异步和同步代码通常是一个坏主意,它会增加冗余阻塞线程的数量并促进死锁。

相反,使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,请查看 Stephen Toub 的“我应该为同步方法公开异步包装器吗?” “我应该为同步方法公开异步包装器吗?”


Chr*_*Fin 2

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

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;

}
Run Code Online (Sandbox Code Playgroud)

await连续使用三个任务不会并行运行任务。它只会在等待时释放线程(如果您使用await Task.Delay(ms)asThread.Sleep(ms)是阻塞操作),但当前执行不会在“睡眠”task2时继续task1