我想知道:
- POSIX AIO 的目的是什么?考虑到我能找到的最明显的实现例子都说它不支持套接字,整个东西对我来说似乎很奇怪。它只是为异步磁盘 I/O 而设计的吗?如果是这样,为什么要使用如此超级通用的 API?如果不是这样,为什么磁盘 I/O 是首先被攻击的对象?
- 有什么完整的 POSIX AIO 程序样例供我查看吗?
- 是否有人真正使用它?
- 哪些平台支持 POSIX AIO?它们支持其中的哪些部分?是否有人真正支持似乎承诺的“任何 FD 的任何 I/O”?
使用kqueue、epoll、IO完成端口等机制可以高效地进行套接字I/O。异步文件I/O算是后来者(除了Windows的重叠I/O和Solaris对POSIX AIO的早期支持)。
如果您想进行套接字I/O,最好使用上述机制之一。
因此,AIO的主要目的是解决异步磁盘I/O的问题。这很可能是为什么Mac OS X仅支持常规文件的AIO,而不支持套接字(因为kqueue在这方面做得更好)。
写操作通常由内核缓存,并在稍后刷新。例如,当驱动器的读取头恰好经过要写入块的位置时。
但是,对于读操作,如果您希望内核优先处理和排序读取操作,则AIO确实是唯一的选择。以下是内核可以(理论上)比任何用户级应用程序更好地执行此操作的原因:
话虽如此,posix AIO具有相当笨拙的接口,例如:
至于使用posix AIO的实际应用程序,您可以查看lighttpd(lighty),在引入支持时还发布了性能测量。
大多数posix平台现在都支持posix AIO(Linux、BSD、Solaris、AIX、tru64)。Windows通过其重叠文件I/O支持它。我的理解是,只有Solaris、Windows和Linux真正支持异步。文件I/O一直到驱动程序,而其他操作系统则使用内核线程模拟异步。Linux是个例外,它的glibc posix AIO实现使用用户级线程模拟异步操作,而其本地异步I/O接口(io_submit()等)从驱动程序一直到底层都是真正的异步,假设驱动程序支持它。由于所有编写 POSIX 网络服务器的人都使用基于事件、非阻塞的方法,因此网络 I/O 对于 AIO 不是优先级。旧式的 Java "数十亿个阻塞线程" 方法非常糟糕。
磁盘写入 I/O 已经进行了缓冲,磁盘读取 I/O 可以使用像 posix_fadvise 这样的函数预取到缓冲区中。这就使得直接、无缓存的磁盘 I/O 成为 AIO 的唯一有用目的。
直接、无缓存 I/O 只对事务性数据库真正有用,而那些数据库往往会写自己的线程或进程来管理它们的磁盘 I/O。
所以,最终 POSIX AIO 没有提供 任何 有用的作用。不要使用它。
一位libtorrent开发者提供了一份报告:http://blog.libtorrent.org/2012/10/asynchronous-disk-io/
有aio_write - 在glibc中实现; 第一次调用aio_read或aio_write函数会生成多个用户模式线程,aio_write或aio_read将请求发送到该线程,线程执行pread / pwrite操作,完成后将答案发布回被阻塞的调用线程。
还有“真正的”aio - 受内核级别支持(需要libaio,参见io_submit调用http://linux.die.net/man/2/io_submit); 也需要O_DIRECT(也可能不受所有文件系统支持,但主要文件系统都支持它)
请参见此处:
http://lse.sourceforge.net/io/aio.html
aio_write
的许多缺陷在 https://dev59.com/1HVD5IYBdhLWcg3wGXlI#5307557 中已经介绍过了。 - Glyph