首页 / C# 入门教程 / 同步与异步概念

C# 入门教程

同步与异步概念

本教程共 100 篇 · 第 81 篇 · 更新于 2026-07-31 · 约 7 分钟阅读

C#C# 入门教程编程语言异步编程async

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 的价值,就是让你用”看似同步”的写法,表达”实际异步”的流程。

它解决两个痛点:

  1. 界面不卡顿。下载文件时 UI 仍可点击,不会”假死”。
  2. 服务端能撑更多请求。一个线程不再被 IO 死死占住。
Note

async/await 不是让任务变快,而是让等待期间不浪费线程。该算多久还是多久。

异步不等于并行

异步(asynchronous)和并行(parallel)常被混为一谈。异步是一个人边等水开边磨豆;并行是叫两个人,一个烧水一个磨豆。

一个人也能异步,因为”等”的时候本就不费手。并行需要多个线程同时算,适合 CPU 密集型。

下面这段用 Task.Delay 模拟”等三秒”的 IO 操作:

async Task MakeCoffeeAsync()
{
    Console.WriteLine("开始烧水");
    await Task.Delay(3000); // 模拟等待,不阻塞线程
    Console.WriteLine("水开了,冲咖啡");
}

await MakeCoffeeAsync();

注意 await Task.Delay 期间,线程可以去干别的事,而不是傻等三秒。

什么时候用异步

遇到下面场景,优先考虑异步:

  1. 访问网络、调用第三方接口。
  2. 读写大文件或操作数据库。
  3. 写桌面、手机、网页等需要响应界面的程序。

纯计算、且很快能算完的小任务,直接同步写反而简单清晰。

Tip

异步是工具不是教条。IO 等待多就用,纯计算且轻量就别折腾。

新手常见误区

误区一:异步一定更快。错。异步让等待不占线程,但若任务本身很短,加异步反而多了状态机开销,得不偿失。

误区二:异步能替代多线程。两者定位不同,异步偏”等”,并行偏”算”,第 85 章再展开。

误区三:所有方法都该加 async。不必要的 async 只是徒增复杂度,同步能清楚表达的就别硬改。

Note

行业约定:异步方法名以 Async 结尾,如 DownloadAsyncSaveAsync。这是习惯,便于一眼识别。

本章在教程中的位置

概念先立住,代码才好落地。接下来第 82 章看 Task 如何表示”进行中的工作”,第 83 章正式学 async/await 语法,第 86 章学取消与超时。一步步把抽象概念变成可运行代码。

真实程序里的异步长什么样

在网页后端,一个请求可能要查数据库、调第三方接口。若同步写,处理这个请求的线程就得一直干等,服务器能同时服务的人就少。改成异步,等数据库时线程去接别的请求,吞吐量自然上去。

在桌面或手机 App 里,IO 等待若是同步,整个界面会”假死”,用户点哪都没反应。异步让界面线程在等待时继续处理点击和刷新。

Note

异步的价值在”规模”与”体验”:服务端多撑请求,客户端不卡界面。纯命令行小工具感受不明显。

一句话对比

下面这张表把容易混的概念并排看,印象更深:

  • 同步:一行接一行,前句不完后句不动。
  • 异步:发起后先放手,好了再回来收尾。
  • 阻塞:线程被占住,啥也干不了。
  • 非阻塞:线程腾出来,能去干别的。
  • 并发:多件事交替推进,像一个人切菜又看锅。
  • 并行:多件事同时做,像两个人各干各的。
Tip

异步通常伴随非阻塞;但”并行”强调同时算,“并发”强调交替推进。三者维度不同,别硬套等号。

为什么需要语言级支持

早期 .NET 也有异步,但写法别扭:BeginXxx/EndXxx 的 APM 模式靠回调,或用事件驱动的 EAP 模式,逻辑被拆得支离破碎,错误处理尤其痛苦。

async/await(C# 5 引入)把这些样板收进编译器,让你用接近同步的顺序写异步。这是语言层面给的”糖”,甜在可读、好调、易维护。

Note

语法糖不神奇:编译器把 async 方法改写成状态机,await 是状态机里的”暂停点”。你写起来像同步,跑起来是异步。

小结

同步阻塞像排队干等,异步非阻塞像见缝插针。async 让异步代码读起来像同步,解决了回调混乱,主要造福 IO 密集型场景。记住:异步省的是等待时的线程,不省计算本身。