任务 with/wihout 异步并等待

Task with/wihout async and await

我有这个方法:

public static Task TaskMethod ()
{
    Task.Delay(30000); 
    return Task.Run(() => Console.WriteLine("From Task") ); 
}

如果我这样称呼它:

public static async Task Main()
{
    Console.WriteLine("before calling the task");
    TaskMethod();
    Console.WriteLine("after calling the task"); 
    Console.ReadLine(); 
}

我有这个输出:

before calling the task
after calling the task
From Task

但是如果我这样称呼:

public static async Task Main()
{
    Console.WriteLine("before calling the task");
    await TaskMethod();
    Console.WriteLine("after calling the task"); 
    Console.ReadLine(); 
}

我有这个结果:

before calling the task
From Task
after calling the task

这种行为正常吗?为什么我可以在不使用异步的情况下等待任务?
我错过了什么?

我会尽力解释。

案例:你不等待返回值然后它会执行该行并继续执行下一个。

Console.WriteLine("before calling the task"); // execute 1
TaskMethod();                                 // execute 2
Console.WriteLine("after calling the task");  // execute 3

你得到的令人困惑的输出是因为你的机器执行第三条命令所需的时间少于执行第二条命令所需的时间(创建任务、启动它、打印到控制台)。第二次调用 运行s 与第三次并行。这也是因为 Task.Delay 调用没有等待,因为你没有 await 它,同样的原则适用于这里。

为了给你一点示例性证据,这里有一段代码在第二次和第三次调用之间引入了轻微的同步延迟:

public static async Task Main()
{
    Console.WriteLine("before calling the task");
    TaskMethod();
    Thread.Sleep(50);
    Console.WriteLine("after calling the task");
    //Console.ReadLine();
}

这使第二次调用的开始在执行第三步之前有更多的时间执行。你得到输出:

before calling the task
From Task
after calling the task

现在,方法 Main 运行 实际上是在主线程上同步的。来自 LINQPad 的屏幕截图显示 Visual Studio 也会显示的消息:

它告诉你main方法会阻塞主线程直到它完成。因为里面没有await。

Main 中的 TaskMethod 将 运行 异步并行于主线程上 运行 的下一个命令!谁跑得快,谁就可以打印它的消息。

为什么 Task.Delay 调用没有 await 就没用了?=!

Delay 方法 returns 启动的任务,实际上与您的 TaskMethod 完全一样。如果你不等待这个延迟任务,它会运行并行。从而消除了延迟的全部影响。你实际上应该注意到你的控制台同时打印所有 3 行,第二行和第三行之间没有延迟!

Why I'm allowed to await the task without using async?

因为 async 的必要性总是指调用 await 的方法,而不是 等待的方法!这可以从您不能简单地向 Task.Delay 调用添加 await 的事实中看出,因为 TaskMethod 未声明为 async!

(希望)最后编辑:

await 运算符需要一个 Task 可以等待其执行,并且因为您的 TaskMethod returns 可以应用 Task 运算符。 如果你接受返回任务,你可以用它做一些美好的事情。然后您可以决定何时等待它的执行结束!:

public static async Task Main()
{
    Console.WriteLine("before calling the task");
    Task taskToBeAwaitedMuchLater = TaskMethod();
    Console.WriteLine("after calling the task");
    await taskToBeAwaitedMuchLater;
    Console.WriteLine("after awaiting the result of the task");
    //Console.ReadLine();
}

输出:

before calling the task
after calling the task
From Task
after awaiting the result of the task