異步I/O
異步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 |
Windows操作系統的異步I/O
編輯Windows提供多種異步I/O(也稱重疊I/O)方式:[3]
設備內核對象
編輯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操作是否完成。[4]該函數檢查OVERLAPPED結構中的Internal成員的值是否為STATUS_PENDING來判斷異步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操作通過ReadFileEx/WriteFileEx函數指出完成過程回調函數。回調函數在該線程的可喚醒等待(alertable wait)中被執行。
使用CreateIoCompletionPort函數創建一個完成端口。然後把文件句柄綁定到這個完成端口(通過CreateIoCompletionPort函數)。這個文件句柄上的異步I/O操作完成時,會自動向這個完成完成端口發通知。線程通過GetQueuedCompletionStatus函數等待這個完成端口上的完成通知,然後從GetQueuedCompletionStatus的調用返回處恢復線程執行。
使用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完成对象
參見
編輯參考文獻
編輯- ^ aio - POSIX asynchronous I/O overview. Linux manual page. [2020-08-25]. (原始內容存檔於2020-04-12).
- ^ Ringing in a new asynchronous I/O API. LWN.net. [2020-08-25]. (原始內容存檔於2020-07-09).
- ^ Description from .NET Framework Developer's Guide. [2017-12-16]. (原始內容存檔於2018-06-14).
- ^ MSDN:GetOverlappedResult function. [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