
理解阻塞、非阻塞、同步、异步这四个概念,核心是抓住两个关键维度:“调用者是否等待结果”(阻塞 / 非阻塞)和 操作“结果通知方式是否主动”(同步 / 异步)。它们并非对立关系(如 “阻塞≠同步”“非阻塞≠异步”),而是从不同角度描述程序的执行模式,常用于网络请求、文件 IO、多线程等场景。
一、搞懂基础:“调用者” 与 “被调用者”
在所有 IO 或任务执行场景中,都存在两个角色:
调用者:发起请求的一方(如主线程、业务代码)。
被调用者:处理请求的一方(如操作系统 IO 模块、网络库、子线程)。
四个概念的区别,本质是 “调用者如何与被调用者交互” 的差异。
二、阻塞(Blocking)与非阻塞(Non-Blocking):调用者是否 “等待”
这组概念描述的是调用者在发起请求后,是否会暂停执行、等待被调用者返回结果—— 核心是 “调用者的状态”。
1. 阻塞(Blocking):调用者一直等待,
当调用者发起请求后,会暂停当前线程的执行,直到被调用者完成任务并返回结果,才继续执行后续代码。此时调用者处于 “阻塞状态”,期间无法处理任何其他任务。
典型场景:
同步文件读取:主线程发起读文件请求后,会等待硬盘读写完成,期间主线程卡住,如果大数据文件,可能UI卡顿。
特点:
逻辑简单:代码按 “发起请求→等结果→处理结果” 的顺序执行,无需额外处理 “结果未到” 的情况。
效率低:调用者等待期间资源被浪费(如主线程阻塞会导致 UI 卡顿)。
2. 非阻塞(Non-Blocking):调用者 “不等”,继续干活
当调用者发起请求后,被调用者会立即返回一个 “临时结果”(如 “任务正在处理中”“还没好”),调用者不会暂停执行,而是继续处理其他任务。调用者需要通过 “轮询”(反复询问被调用者 “好了没”)或 “回调”(被调用者完成后主动通知)来获取最终结果 —— 相当于 “发了快递后先去上班,时不时查物流(轮询),或等快递员打电话(回调)”。
典型场景:
异步文件 IO:发起读文件请求后,主线程继续执行,等硬盘读写完成后通过事件通知主线程。
特点:
效率高:调用者不浪费时间等待,可并行处理其他任务(如 UI 线程非阻塞时,用户能正常点击按钮)。
逻辑复杂:需要处理 “任务未完成” 的临时状态,可能需要轮询或回调机制。
三、同步(Synchronous)与异步(Asynchronous):结果如何 “通知” 调用者
这组概念描述的是被调用者完成任务后,如何将结果传递给调用者—— 核心是 “结果的通知方式”。
1. 同步(Synchronous):调用者 “主动要” 结果
被调用者完成任务后,不会主动通知调用者,而是需要调用者 “主动获取结果”(可能是 “等待到结果”,也可能是 “轮询到结果”)。本质是 “调用者主导结果的获取”。
关键结论:同步≠阻塞!同步可以是阻塞的,也可以是非阻塞的:
阻塞式同步(最常见):调用者发起请求后,等待被调用者完成并主动返回结果(如同步文件读取)。
非阻塞式同步:调用者发起请求后,继续干活,同时定期轮询被调用者 “结果好了没”(如非阻塞 Socket 的轮询检查)。
特点:
调用者需主动关注结果状态,逻辑较繁琐(如轮询需写循环判断)。
结果获取的时机由调用者控制(但可能错过 “结果刚完成” 的时机)。
2. 异步(Asynchronous):被调用者 “主动给” 结果
当调用者发起请求时,会同时告知被调用者:“你完成后,通过这个回调函数 / 事件通知我”。被调用者在后台处理任务,完成后会主动触发回调函数或发送事件,将结果传递给调用者 —— 相当于 “快递到了,快递员主动打电话通知你(回调),你不用自己查”。
关键结论:异步必定是非阻塞的!由于调用者发起请求后不会等待,而是由被调用者主动通知,调用者可继续处理其他任务。
典型场景:
异步 HTTP 请求(如IdHTTP.GetAsync(url, 回调函数)):主线程发起请求后继续处理 UI,等网络请求完成后,回调函数被触发,处理响应数据。
多线程异步任务(如TTask.Run(任务).ContinueWith(回调)):子线程执行任务,主线程不等待,子线程完成后通过ContinueWith通知主线程。
特点:
效率最高:调用者完全无需关注结果获取,只需在回调中处理结果,资源利用率高。
逻辑较复杂:回调可能导致 “回调地狱”(多个异步任务嵌套),需注意线程安全(如 UI 线程回调需同步)。
三、阻塞/非阻塞,同步/异步的组合分析。
以用户去快递的方式,解释两者之间的组合。

四、实例
根据开发的使用频率,目前列举了“阻塞同步”,“非阻塞异步”的两个实例。
1、阻塞同步
关键代码

2、非阻塞异步





