Linux异步IO实现方案总结
一、glibc aio
1、名稱
由于是glibc提供的aio函數庫,所以稱為glibc aio。
glibc是GNU發布的libc庫,即c運行庫。
另外網上還有其他叫法posix aio,都是指glibc提供的這套aio實現方案。
2、主要接口
glibc aio主要包含如下接口:
| 函數?? ? | 功能 |
| int aio_read(struct aiocb *aiocbp);?? | ?提交一個異步讀 |
| int aio_write(struct aiocb *aiocbp);?? ? | 提交一個異步寫 |
| int aio_cancel(int fildes, struct aiocb *aiocbp);?? ? | 取消一個異步請求(或基于一個fd的所有異步請求,aiocbp==NULL) |
| int aio_error(const struct aiocb *aiocbp);?? ? | 查看一個異步請求的狀態(進行中EINPROGRESS?還是已經結束或出錯?) |
| ssize_t aio_return(struct aiocb *aiocbp);?? ? | 查看一個異步請求的返回值(跟同步讀寫定義的一樣) |
| int aio_suspend(const struct aiocb * const list[], int nent, const struct timespec *timeout);?? | 阻塞等待請求完成 |
glibc aio提供函數API,是比較通俗易懂的。
3、實現原理
在glibc aio的實現原理是,用多線程同步來模擬異步IO。實際上,為了避免線程的頻繁創建、銷毀,當有多個請求時,glibc aio會使用線程池,但以上原理是不會變的,尤其要注意的是:我們的回調函數是在一個單獨線程中執行的。
缺點: glibc aio 廣受非議,存在一些難以忍受的缺陷和bug,飽受詬病,是極不推薦使用的。詳見:http://davmac.org/davpage/linux/async-io.html
二、libaio
1、名稱
libaio是由linux內核提供的aio實現方案,類似于windows api。
由于是linux kernel提供的api,故也叫linux kernel aio,或者原生aio,
native aio。
由于linux下aio實現方式較多,網上叫法很亂,所以這里特意總結下,方便大家區分。
2、主要接口
它主要包含如下系統調用接口:
| 函數 | 功能 |
| int io_setup(int maxevents, io_context_t *ctxp);?? ? | 創建一個異步IO上下文(io_context_t是一個句柄) |
| int io_destroy(io_context_t ctx);?? ? | 銷毀一個異步IO上下文(如果有正在進行的異步IO,取消并等待它們完成) |
| long io_submit(aio_context_t ctx_id, long nr, struct iocb **iocbpp);?? ? | 提交異步IO請求 |
| long io_cancel(aio_context_t ctx_id, struct iocb *iocb, struct io_event *result);?? ? | 取消一個異步IO請求 |
| long io_getevents(aio_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout)?? ? | 等待并獲取異步IO請求的事件(也就是異步請求的處理結果) |
其中,struct iocb主要包含以下字段:
iocb 是提交IO任務時用到的,可以完整地描述一個IO請求:
- data是留給用來自定義的指針:可以設置為IO完成后的callback函數;
- aio_lio_opcode表示操作的類型:IO_CMD_PWRITE | IO_CMD_PREAD;
- aio_fildes是要操作的文件:fd;
- io_iocb_common中的buf, nbytes, offset分別記錄的IO請求的mem buffer,大小和偏移。
io_event是用來描述返回結果的:
- obj就是之前提交IO任務時的iocb;
- res和res2來表示IO任務完成的狀態。
3、實現原理
libaio與Glibc的多線程模擬不同 ,它是真正做到內核的異步通知,是真正意義上的異步IO。
聽起來Kernel Native AIO幾乎提供了近乎完美的異步方式,但如果你對它抱有太高期望的話,你會再一次感到失望。
使用限制: 目前libaio僅支持O_DIRECT標志,即僅支持Direct I/O。
Direct I/O可以簡單理解為直接讀寫IO,讀寫期間無緩存。
Linux中直接I/O機制介紹:
https://www.ibm.com/developerworks/cn/linux/l-cn-directio/index.html
缺點: 目前libaio僅支持Direct I/O方式來對磁盤讀寫,這意味著,你無法利用系統的緩存,同時它要求讀寫的的大小和偏移要以區塊的方式對齊。
三、libeio
在當年,linux下已有的AIO (異步IO)解決方案:
- Glibc的AIO,在用戶態,多線程同步來模擬的異步IO;
- libaio,需要linux內核2.6.22以上,且僅支持Direct I/O。
但兩者都存在讓使用者望而卻步的問題:
- Glibc的AIO bug太多,而且IO發起者并不是最后的IO終結者(callbak是在單獨的線程執行的);
- libaio只支持O_DIRECT方式,無法利用Page cache。
正是由于上述原因,Marc Alexander Lehmann大佬決定自己開發一個AIO庫,即 libeio。
libeio也是在用戶態用多線程同步來模擬異步IO,但實現更高效,代碼也更可靠,目前雖然是beta版,但已經可以上生產了(node.js底層就是用libev和libeio來驅動的)。
還要強調點:libeio里IO的終結者正是當初IO的發起者(這一點非常重要,因為IO都是由用戶的request而發起,而IO完成后返回給用戶的response也能在處理request的線程中完成)。
libeio提供全套異步文件操作的接口,讓使用者能寫出完全非阻塞的程序。
缺點: 嚴格來講,libeio也不屬于真正的異步IO,仍然是通過用戶態多線程來模擬的,性能上與真正的異步IO有差距。
github地址:https://github.com/kindy/libeio
代碼量不大,幾千行,感興趣可以研究下。
四、io_uring
在過去的數年間,針對上述缺陷,限制的很多改進努力都未果,如Glibc AIO、libaio、libeio。
雖然在使用和性能上提升了很多,但是,在Linux 上,依然沒有比較完美的異步文件IO方案。
直到,Linux 5.1合入了一個新的異步IO框架和實現:io_uring,由block IO大神Jens Axboe開發。
這對當前異步IO領域無疑是一個喜大普奔的消息,這意味著,libaio的時代即將成為過去,io_uring的時代即將開啟。
為了方便使用,Jens Axboe還開發了一套liburing庫,同時在fio中提供了ioengine=io_uring的支持。通過liburing庫,應用不必了解諸多io_uring的細節就可以簡單地使用起來。例如,無需擔心memory barrier,或者是ring buffer管理之類等。
一句話總結 io_uring 就是:一套全新的 syscall,一套全新的 async API,更高的性能,更好的兼容性,來迎接高 IOPS,高吞吐量的未來。
這個特性,才出來,需要5.1以上內核才能支持,具體好不好用,后續才知道,現在似乎搜索到的內容較少。
io_uring使用參考:
《原生的 Linux 異步文件操作,io_uring 嘗鮮體驗》
《Linux 5.1內核AIO 的新歸宿:io_uring》
五、總結
linux異步IO實際上是利用了CPU和IO設備可以異步工作的特性(IO請求提交的過程主要還是在調用者線程上同步完成的,請求提交后由于CPU與IO設備可以并行工作,所以調用流程可以返回,調用者可以繼續做其他事情)。
linux的異步IO發展之路,還是比較曲折的,沒有一個完美的實現。不像windows下異步IO,IOCP就是標桿,各種吊打。
在目前情況下,libeio就是比較不錯的方案了。
但是如果你的程序中只用到Direct I/O,那么推薦使用libaio。
在將來,隨著Linux 5.1以上版本的更新,如果io_uring給力的話,linux異步IO很可能就一統天下了。
參考鏈接:
《linux AIO (異步IO) 那點事兒》
《異步I/O – posix aio 從入門到放棄的吐血實踐》
《linux異步IO編程實例分析》
《linux異步IO的兩種方式》
————————————————
版權聲明:本文為CSDN博主「百里楊」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zyhse/article/details/109188990
總結
以上是生活随笔為你收集整理的Linux异步IO实现方案总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 令人迷惑的硬币翻转(洛谷P1146题题解
- 下一篇: 【算法分析与设计】埃氏筛素数算法