什么是异步?
发起一个操作后,不需要一直等待它完成,可以先去做别的事,等它完成后再继续处理结果。
和同步的区别?
同步(Sync):你必须等它做完,才能继续
异步(Async): 你不用等,可以先干别的,完成后再回来处理
生活例子
🍜 同步
你泡方便面:倒水 -> 站着等 5 分钟 -> 吃
这 5 分钟你啥也干不了
🍜 异步
倒水 -> 去刷手机 ->面好了 -> 回来吃
你没有“阻塞自己”
完整例子
1 | using System; |
输出:
1. Main start, ThreadId = 1
4. ReadDataAsync start, ThreadId = 1
2. Main got Task, ThreadId = 1
3. Main can do other work...
7. ReadDataAsync resumed after await, ThreadId = 5
8. Main end, ThreadId = 1
过程拆解
- 进入main 执行
Console.WriteLine($"1. Main start, ThreadId = ...");打印:Main start, ThreadId = 1 - 调用 ReadDataAsync() 执行:
Task task = ReadDataAsync();
它会先同步执行一部分,一直执行到第一个 await 为止。
所以 ReadDataAsync() 被调用后,会先执行:Console.WriteLine($"4. ReadDataAsync start...");于是就会打印4. ReadDataAsync start - 遇到
await Task.Delay(3000);,启动了一个“3秒后完成”的任务,这里是一个假任务,需要耗时3秒,真实情况可能是在读文件、连数据库等操作。 - Main 继续往下执行,遇到了:
Console.WriteLine($"2. Main got Task...");
Console.WriteLine("3. Main can do other work...");
打印:
2. Main got Task
3. Main can do other work...
这就说明:ReadDataAsync 虽然还没真正执行完,但 Main 并没有被卡住。
这就是“异步”的直观体现。
5. Main 执行到 await task,这句的意思不是“立刻继续往下执行”,而是:
等 ReadDataAsync 真正完成后,再继续执行 Main 后面的代码。
所以这时 Main 也暂停了。
在真实的操作中,可能表示在进行下一步操作前,需要等待数据库连接完毕,或者是文件读取完毕,取得了必要的东西后,再进行下一步。
6. 3 秒到了,Task.Delay(3000) 完成。 于是打印 Console.WriteLine($"7. ReadDataAsync resumed after await...");
此时,线程号可能变了,比如从 1 变成 5,这说明:在控制台程序里,await 后恢复执行,不一定回到原来的线程。
7. ReadDataAsync 执行完毕,等到了 await task; 后,程序就结束了,打印 8. Main end
其余小知识点
await task; 这段代码在大多情况下是必需的,它的作用是等待这个异步任务执行完成,再继续往下走,所以它是不是必要,取决于你是否需要保证后面的代码在任务完成之后再执行。
一句话:await task 是否必要取决于业务是否需要等待该异步任务完成。如果后续逻辑依赖任务结果、依赖其完成顺序,或者需要正确处理异常,那么通常是必要的;如果只是启动一个与主流程无关的后台任务,则可以不 await,但这种做法需要谨慎。