首页 > 解决方案 > 为什么同步控制台 Main Method 挂起调用异步方法?

问题描述

我无法理解为什么从控制台应用程序的 Main 方法调用异步方法会永远挂起。我觉得我错过了异步执行的一些关键元素:

static void Main(string[] args)
{
    Console.WriteLine("w3");
        
    var exe = new Exe2();
    exe.Do2().Wait();
        
    Console.WriteLine("/w3");
    Console.ReadKey();
}

public class Exe2
{
    public async Task Do2()
    {
        Task task1 = new Task(() => { Console.WriteLine("t1"); Task.Delay(2000); });
        Task task2 = new Task(() => { Console.WriteLine("t2"); Task.Delay(2000); });
        Task task3 = new Task(() => { Console.WriteLine("t3"); Task.Delay(2000); });

        await Task.WhenAll(task1, task2, task3);
    }
}

上面的代码打印 w3 没有别的,也没有采用ReadKey任何一个。

标签: c#asynchronousasync-await

解决方案


你还没有开始你的任务,Task.WhenAll本质上是要永远等待。你需要打电话Start

启动 Task,将其调度到当前 TaskScheduler 执行。

task1.Start();
task2.Start();
task3.Start();

await Task.WhenAll(task1, task2, task3);

然而:除非你绝对知道你需要它,否则永远不要使用Task构造函数,它对于没有经验的编码人员有几个非常大的陷阱,例如只支持动作委托并且需要启动。相反,总是使用whichTask.Run将启动您的任务

Task task1 = Task.Run(() => { Console.WriteLine("t1"); Task.Delay(2000); });
Task task2 = Task.Run(() => { Console.WriteLine("t2"); Task.Delay(2000); });
Task task3 = Task.Run(() => { Console.WriteLine("t3"); Task.Delay(2000); });

尽管不是您的问题,但您永远不需要在现代 .net中调用Wait或调用异步方法。相反,使用异步重载Result Main

static async Task Main(string[] args)
{
    Console.WriteLine("w3");
    
    var exe = new Exe2();
    await exe.Do2();
    
    Console.WriteLine("/w3");
    Console.ReadKey();
}

推荐阅读