API调用中,同步(Synchronous)异步(Asynchronous)是描述操作执行方式的核心概念,决定了调用方(通常是应用程序)在发起操作后如何等待结果,直接影响程序的性能和响应性。

核心定义

同步 API:调用后,发起操作的线程会阻塞(暂停执行),直到操作完全完成(成功或失败)才返回结果,继续执行后续代码。
通俗点讲就是:“只能等这一步操作做完,我才能往下”。
异步 API:调用后,操作会在后台(由系统或其他线程)执行,函数立即返回,发起操作的线程可以继续执行其他任务;操作完成后,通过预设的机制(如事件、回调函数)通知调用方结果。
通俗点讲就是:“这一步操作你先做着,我去忙别的,做完了记得通知我”。

关键区别与特定

维度 同步 API 异步 API
线程行为 | 调用线程阻塞,直到操作完成 | 调用线程不阻塞,立即返回,可继续执行其他任务
执行效率 | 单任务场景简单直接,但高并发时阻塞会浪费线程资源 | 不阻塞线程,适合高并发,资源利用率更高
复杂度 | 逻辑简单,无需处理 “操作未完成” 的中间状态 | 逻辑复杂,需处理 “操作发起后、完成前” 的状态,以及结果通知机制
结果获取时机 | 函数返回时直接获取结果 | 操作完成后通过通知机制(如事件、回调)获取结果

结合Windows API的示例

WriteFile函数为例:
1. 同步模式(lpOverlapped = NULL)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 同步写入:调用后线程阻塞,直到写入完成
DWORD bytesWritten;
BOOL success = WriteFile(
hFile, // 文件句柄
data, // 待写入数据
dataSize, // 写入字节数
&bytesWritten, // 接收实际写入字节数
NULL // 同步模式:lpOverlapped为NULL
);
// 代码执行到这里时,写入操作已完成(成功或失败)
if (success) {
printf("写入完成,共写入 %d 字节\n", bytesWritten);
}

线程在WriteFile调用期间 “暂停”,直到数据写入完成(可能是几毫秒到几秒,取决于数据量和设备速度)。
适合场景:简单的小文件写入、对响应速度要求不高的单任务场景。

异步模式(lpOverlapped 为有效结构体)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1. 初始化OVERLAPPED结构体(含事件通知)
OVERLAPPED ov = {0};
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // 创建事件对象

// 2. 异步写入:调用后立即返回,写入在后台执行
BOOL success = WriteFile(
hFile, // 文件句柄(需以FILE_FLAG_OVERLAPPED打开)
data, // 待写入数据
dataSize, // 写入字节数
NULL, // 异步模式:忽略此参数
&ov // 传入OVERLAPPED结构体
);

// 3. 调用后线程不阻塞,可立即执行其他任务(如处理UI、接收其他请求)
printf("写入操作已发起,继续处理其他任务...\n");

// 4. 等待操作完成(通过事件通知)
WaitForSingleObject(ov.hEvent, INFINITE); // 等待事件变为“有信号”

// 5. 获取实际写入字节数
DWORD bytesWritten;
GetOverlappedResult(hFile, &ov, &bytesWritten, FALSE);
printf("异步写入完成,共写入 %d 字节\n", bytesWritten);

WriteFile调用后立即返回,线程可以继续执行其他逻辑;写入操作在后台完成后,ov.hEvent事件被激活,通过WaitForSingleObject或完成端口等机制感知结果。
适合场景:高并发服务器(如同时处理上千个文件写入请求)、UI 程序(避免界面卡顿)。

异步API的通知机制

事件对象(Event):如上述 OVERLAPPED.hEvent,操作完成后事件变为 “有信号”,调用方通过WaitForSingleObject等待。
回调函数(Callback):API 允许传入一个函数指针,操作完成后系统自动调用该函数(如WriteFileExlpCompletionRoutine)。
I/O 完成端口(Completion Port):Windows高并发场景的最优选择,多个异步操作的结果统一通过一个端口通知,减少线程切换开销。