了解异步方法中的“await”用法

Muh*_*een 2 c# async-await

我正在运行以下代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Threading;

public class Program
{
    public static void Main()
    {
        new Program().Test();
    }
        
    public async Task Test() 
    {
        Console.WriteLine("starting...");
        await Test2();
        Console.WriteLine("done!");
        Thread.Sleep(2*1000);
    }
        
    public async Task Test2() 
    {
        Console.WriteLine("Task in delay...");
        await Task.Delay(5000);
    }
            
}
Run Code Online (Sandbox Code Playgroud)

我期望输出是:

starting...
task in delay...
done!
Run Code Online (Sandbox Code Playgroud)

但是,当我运行代码时,我得到:

starting...
Task in delay...
Run Code Online (Sandbox Code Playgroud)

并且程序终止。我错过了什么吗?我应该如何修改代码才能得到预期的结果?

另一个问题 - 根据我的理解,await方法中最后一行的 using 是多余的,如果我删除它,我该如何await在该方法上?

Mar*_*ell 7

我错过了什么吗?

是的; 你没有等到Test

    public static async Task Main()
    {
        await new Program().Test();
    }
Run Code Online (Sandbox Code Playgroud)

如果没有这个,Main一旦Test返回就会立即完成,这将是第一次await遇到不完整的情况 -async链从Task.Delay(这将是不完整的)展开,将其余的工作留在后台Test/Test2安排在后台;由于没有剩余的非后台线程,因此该进程退出。

请注意,您可以删除任务,asyncreturn

    public static Task Main()
        => new Program().Test();
Run Code Online (Sandbox Code Playgroud)

其工作方式非常相似,尽管它稍微改变了重新同步异常的语义。如有疑问:await

  • @MuhammadJabarin 那么你使用的是一个非常旧的编译器版本;我建议解决这个问题;你*可以*手动解决这个问题,但老实说:只需更新编译器 - 黑客黑客将是`new Program().Test().Wait();`,但是**请**不要养成这个习惯调用 `Wait()` (或 `.Result`) - 正确的次数基本上为零 (3认同)
  • ...如果你*不*使用 `async`/`await`,这种情况会直接暴露为同步异常;大多数人会说“await”结果是更好的结果,但是*在某些高容量场景中*,在不是 100% 需要时避免该机器是有用的,并接受它可能抛出而不是返回的事实有缺陷的任务;此外,这两种情况之间的堆栈跟踪详细信息和异常类型可能会略有不同。正如我之前所说:如果有疑问,请“等待” (3认同)
  • @MuhammadJabarin,您*可以*在“return”和“await”之间进行更改的唯一一次是当方法中只有一个“await”时,在最后一行,它返回完全相同的形状(“ValueTask[<T>] ` 等)您要返回 - 并且要使用 `return` 而不是 `await`,您需要删除 `async` - 但不,这并不*完全*相同;区别在于,如果您调用的方法*同步*抛出,特别是实际的抛出,而不是“我正在返回一个错误的任务”,会发生什么;如果您使用 `async`/`await`,编译器会将其包装起来并返回一个错误的任务;然而... (2认同)