同步与异步概念
本教程共 100 篇 · 第 81 篇 · 更新于 2026-07-31 · 约 7 分钟阅读
81. 同步与异步概念
本节目标:学完能区分阻塞与非阻塞、CPU 密集与 IO 密集,明白 async 到底解决什么问题。
从煮咖啡说起
想象你烧水冲咖啡。烧水要等三分钟,如果你就站在水壶前干瞪眼,什么也不做,这就是”同步”——你被烧水这件事”阻塞(block)“了。
如果你趁烧水的时候去磨豆、洗杯子,水开了再回来冲,这便是”异步(asynchronous)“。你没有被烧水卡住,三分钟里干了更多活。
电脑里的程序也一样。一条语句没跑完,后面只能等着,这叫阻塞;不必干等、先去处理别的事,就是非阻塞。
阻塞与非阻塞的区别
阻塞(blocking)指当前线程停在原地,直到任务返回结果才往下走。非阻塞(non-blocking)指线程发出请求后立刻腾出手,等结果好了再回来继续。
新手常把”卡住”当成理所当然。其实在大程序里,一个线程被长期阻塞,等于白白浪费了一份算力。
Note线程(thread)是程序执行的最小单位。一个线程被阻塞,谁来干活就得另开线程,而开线程也有成本。
CPU 密集与 IO 密集
判断该不该异步,先看任务是哪一类。
CPU 密集型(CPU-bound):任务主要靠处理器算,比如排序、加密、图像压缩。这类活儿占满 CPU,多开线程未必更快,反而可能因切换开销变慢。
IO 密集型(IO-bound):任务在等外部设备,比如读文件、访问数据库、请求网络。CPU 在等待期间其实闲着,这时让线程去干别的,整体效率就上来了。
Tip一句话记:算得多用 CPU,等得久用 IO。异步主要帮 IO 密集型任务省时间。
async 解决什么问题
没有语言支持时,写异步要靠回调(callback)或事件,代码会绕成一团,原本的顺序逻辑被切碎。async/await 的价值,就是让你用”看似同步”的写法,表达”实际异步”的流程。
它解决两个痛点:
- 界面不卡顿。下载文件时 UI 仍可点击,不会”假死”。
- 服务端能撑更多请求。一个线程不再被 IO 死死占住。
Noteasync/await 不是让任务变快,而是让等待期间不浪费线程。该算多久还是多久。
异步不等于并行
异步(asynchronous)和并行(parallel)常被混为一谈。异步是一个人边等水开边磨豆;并行是叫两个人,一个烧水一个磨豆。
一个人也能异步,因为”等”的时候本就不费手。并行需要多个线程同时算,适合 CPU 密集型。
下面这段用 Task.Delay 模拟”等三秒”的 IO 操作:
async Task MakeCoffeeAsync()
{
Console.WriteLine("开始烧水");
await Task.Delay(3000); // 模拟等待,不阻塞线程
Console.WriteLine("水开了,冲咖啡");
}
await MakeCoffeeAsync();
注意 await Task.Delay 期间,线程可以去干别的事,而不是傻等三秒。
什么时候用异步
遇到下面场景,优先考虑异步:
- 访问网络、调用第三方接口。
- 读写大文件或操作数据库。
- 写桌面、手机、网页等需要响应界面的程序。
纯计算、且很快能算完的小任务,直接同步写反而简单清晰。
Tip异步是工具不是教条。IO 等待多就用,纯计算且轻量就别折腾。
新手常见误区
误区一:异步一定更快。错。异步让等待不占线程,但若任务本身很短,加异步反而多了状态机开销,得不偿失。
误区二:异步能替代多线程。两者定位不同,异步偏”等”,并行偏”算”,第 85 章再展开。
误区三:所有方法都该加 async。不必要的 async 只是徒增复杂度,同步能清楚表达的就别硬改。
Note行业约定:异步方法名以
Async结尾,如DownloadAsync、SaveAsync。这是习惯,便于一眼识别。
本章在教程中的位置
概念先立住,代码才好落地。接下来第 82 章看 Task 如何表示”进行中的工作”,第 83 章正式学 async/await 语法,第 86 章学取消与超时。一步步把抽象概念变成可运行代码。
真实程序里的异步长什么样
在网页后端,一个请求可能要查数据库、调第三方接口。若同步写,处理这个请求的线程就得一直干等,服务器能同时服务的人就少。改成异步,等数据库时线程去接别的请求,吞吐量自然上去。
在桌面或手机 App 里,IO 等待若是同步,整个界面会”假死”,用户点哪都没反应。异步让界面线程在等待时继续处理点击和刷新。
Note异步的价值在”规模”与”体验”:服务端多撑请求,客户端不卡界面。纯命令行小工具感受不明显。
一句话对比
下面这张表把容易混的概念并排看,印象更深:
- 同步:一行接一行,前句不完后句不动。
- 异步:发起后先放手,好了再回来收尾。
- 阻塞:线程被占住,啥也干不了。
- 非阻塞:线程腾出来,能去干别的。
- 并发:多件事交替推进,像一个人切菜又看锅。
- 并行:多件事同时做,像两个人各干各的。
Tip异步通常伴随非阻塞;但”并行”强调同时算,“并发”强调交替推进。三者维度不同,别硬套等号。
为什么需要语言级支持
早期 .NET 也有异步,但写法别扭:BeginXxx/EndXxx 的 APM 模式靠回调,或用事件驱动的 EAP 模式,逻辑被拆得支离破碎,错误处理尤其痛苦。
async/await(C# 5 引入)把这些样板收进编译器,让你用接近同步的顺序写异步。这是语言层面给的”糖”,甜在可读、好调、易维护。
Note语法糖不神奇:编译器把 async 方法改写成状态机,await 是状态机里的”暂停点”。你写起来像同步,跑起来是异步。
小结
同步阻塞像排队干等,异步非阻塞像见缝插针。async 让异步代码读起来像同步,解决了回调混乱,主要造福 IO 密集型场景。记住:异步省的是等待时的线程,不省计算本身。