**异步I/O**是计算机操作系统对输入输出的一种处理方式：发起I/O请求的线程不等I/O操作完成，就继续执行随后的代码，I/O结果用其他方式通知发起I/O请求的程序。与异步I/O相对的是更为常见的"同步（阻塞）I/O"：发起I/O请求的线程不从正在调用的I/O操作函数返回（即被阻塞），直至I/O操作完成。

类Unix操作系统与POSIX
---------------

POSIX提供下述API函数：

|  | 阻塞 | 非阻塞 |
| --- | --- | --- |
| 同步 | write, read | write, read + poll / select |
| 异步 | - | aio\_write, aio\_read |

* aio
* io\_uring (Linux 5.1以後支援)

Windows操作系统的异步I/O
-----------------

Windows提供多种异步I/O（也称重叠I/O）方式：

### 设备内核对象

I/O设备在操作系统内核中表示为内核对象，因此具有可等待（waitable）内核对象状态。例如：文件句柄，线程句柄等等。对于文件内核对象，当一个异步I/O完成后，该文件句柄被置为触发态。使用这种方式获取异步I/O完成的通知，缺点是如果在一个文件内核对象上同时有多个异步I/O操作，只通过文件句柄的触发无法辨识哪个异步I/O操作完成了。

例子：

```
HANDLE hFile = CreateFileW(L"d:\\a.txt", GENERIC\_WRITE, 0, 0, CREATE\_ALWAYS, FILE\_FLAG\_OVERLAPPED, 0); //设置异步IO的标志FILE\_FLAG\_OVERLAPPED
char buffer[10] = {"abcd"};
OVERLAPPED ol = { 0 };//用0初始化OVERLAPPED的结构
ol.Offset = 2;/从文件的第三个字节开始IO
BOOL rt = WriteFile(hFile, buffer, 5, NULL, &ol);//发起一个异步写操作
//SetFileCompletionNotificationModes(hFile, FILE\_SKIP\_SET\_EVENT\_ON\_HANDLE);//如此设置则文件内核对象就不会被触发
if (rt == FALSE && GetLastError() == ERROR\_IO\_PENDING)//检查异步IO是否完成 
{
 WaitForSingleObject(hFile, INFINITE);//等待设备内核对象（文件）被触发。
}
CloseHandle(hFile);

```

### GetOverlappedResult函数

也可以使用Windows API函数GetOverlappedResult直接阻塞/非阻塞等待指定的异步I/O操作是否完成。该函数检查OVERLAPPED结构中的Internal成员的值是否为STATUS\_PENDING来判断异步I/O是否完成。 

### 异步I/O操作的完成通知用事件内核对象

在异步I/O操作的read/write函数调用中给出的OVERLAPPED类型的参数中，可以指定一个内核事件对象。这个异步I/O操作完成时，这个内核事件对象会被触发。从而，等待在这个事件对象上的程序就会知道这个异步I/O操作完成。

例子：

```
HANDLE hFile = CreateFileW(L"d:\\a.txt", GENERIC\_WRITE, 0, 0, CREATE\_ALWAYS, FILE\_FLAG\_OVERLAPPED, 0); //设置异步IO的标志FILE\_FLAG\_OVERLAPPED
char buffer[10] = {"abcd"};
OVERLAPPED ol = { 0 };//用0初始化OVERLAPPED的结构
ol.Offset = 2;/从文件的第三个字节开始IO
HANDLE hEvent = CreateEvent(0, FALSE, FALSE, NULL); 
ol.hEvent = hEvent;//传递一个事件对象。 

BOOL rt = WriteFile(hFile, buffer, 5, NULL, &ol);//发起一个异步写操作 

if (rt == FALSE && GetLastError() == ERROR\_IO\_PENDING)//检查异步IO是否完成 
{
 WaitForSingleObject(ol.hEvent, INFINITE);//等待设备内核对象（文件）被触发。
}
CloseHandle(hEvent); 
CloseHandle(hFile);

```

### 可唤醒I/O

异步可唤醒I/O操作通过ReadFileEx/WriteFileEx函数指出完成过程回调函数。回调函数在该线程的可唤醒等待（alertable wait）中被执行。

### 完成端口

使用CreateIoCompletionPort函数创建一个完成端口。然后把文件句柄绑定到这个完成端口（通过CreateIoCompletionPort函数)。这个文件句柄上的异步I/O操作完成时，会自动向这个完成完成端口发通知。线程通过GetQueuedCompletionStatus函数等待这个完成端口上的完成通知，然后从GetQueuedCompletionStatus的调用返回处恢复线程执行。

### 线程池I/O完成对象

使用CreateThreadpoolIo函数创建一个I/O完成对象，绑定了要执行异步I/O操作的文件句柄与待执行的回调函数。通过StartThreadpoolIo函数开始I/O完成对象的工作。每当绑定的文件句柄上的异步I/O操作完成，自动调用线程池上的线程执行指定的回调函数。

例子：

```
VOID CALLBACK OverlappedCompletionRoutine(PTP\_CALLBACK\_INSTANCE pInstance, 
 PVOID pvContext, 
 PVOID pOverlapped, 
 ULONG IoResult, 
 ULONG\_PTR NumberOfBytesTransferred, 
 PTP\_IO pIo) 
{ 
 printf("OverlappedCompletionRoutine, transferred: %d bytes\n", NumberOfBytesTransferred); 
} 

HANDLE hFile = CreateFileW(L"d:\\a.txt", GENERIC\_WRITE, 0, 0, CREATE\_ALWAYS, FILE\_FLAG\_OVERLAPPED, 0); //设置异步IO的标志FILE\_FLAG\_OVERLAPPED

PTP\_IO pio = CreateThreadpoolIo(hFile, OverlappedCompletionRoutine, NULL, NULL);//将设备对象和线程池的IO完成端口关联起来。 
StartThreadpoolIo(pio);
char buffer[10] = {"abcd"};
OVERLAPPED ol = { 0 };//用0初始化OVERLAPPED的结构
ol.Offset = 2;/从文件的第三个字节开始IO 

BOOL rt = WriteFile(hFile, buffer, 5, NULL, &ol);//发起一个异步写操作 
if(rt==FALSE && GetLastError()==ERROR\_IO\_PENDING))
{ 
 ::Sleep(4000); 
 //do somethings... 
}
else
{
 CancelThreadpoolIo(pio); 
}
WaitForThreadpoolIoCallbacks(pio,false);
CloseHandle(hFile); 
CloseThreadpoolIo(pio);//关闭线程池io完成对象

```

参见
--

* IOCP

参考文献
----

1. ↑ . Linux manual page.  [2020-08-25]. （原始内容存档于2020-04-12）.
2. ↑ . LWN.net.  [2020-08-25]. （原始内容存档于2020-07-09）.
3. ↑ .  [2017-12-16]. （原始内容存档于2018-06-14）.
4. ↑ .  [2017-12-16]. （原始内容存档于2017-12-16）.

外部链接
----

* The C10K Problem; a survey of asynchronous I/O methods with emphasis on scaling – by Dan Kegel
* Article "Boost application performance using asynchronous I/O （页面存档备份，存于）" by M. Tim Jones
* Article "Lazy Asynchronous I/O For Event-Driven Servers （页面存档备份，存于）" by Willy Zwaenepoel, Khaled Elmeleegy, Anupam Chanda and Alan L. Cox
* Perform I/O Operations in Parallel （页面存档备份，存于）
* Description from POSIX standard （页面存档备份，存于）
* Inside I/O Completion Ports by Mark Russinovich
* Asynchronous I/O and The Asynchronous Disk I/O Explorer （页面存档备份，存于）
* I/O::AI/O is a Perl module offering an asynchronous interface for most I/O operations （页面存档备份，存于）
* ACE Proactor