POSIX异步I/O(AIO)的状态是什么?

Gly*_*yph 92 linux bsd posix asynchronous aio

网页上散布着各种描述POSIX AIO设施的页面,其中包含不同的细节.它们都不是最近的.目前还不清楚他们究竟在描述什么.例如,Linux内核异步I/O支持的"官方"(?)网站说套接字不起作用,但我的Ubuntu 8.04.1工作站上的"aio.h"手册页似乎都暗示它适用于任意文件描述符.然后还有另一个项目似乎在图书馆层工作,文档更少.

我想知道:

  • POSIX AIO的目的是什么?鉴于我能找到的最明显的实现示例说它不支持套接字,整个事情对我来说似乎很奇怪.它只适用于异步磁盘I/O吗?如果是这样,为什么超通用API?如果没有,为什么磁盘I/O首先受到攻击?
  • 哪些示例完整的 POSIX AIO程序我可以看一下?
  • 有没有人真正使用它,真的吗?
  • 哪些平台支持POSIX AIO?他们支持哪些部分?有没有人真的支持隐含的"对任何FD的任何I/O" <aio.h>似乎有希望?

我可以使用的其他多路复用机制非常好,但随处可见的信息碎片让我很好奇.

Arv*_*vid 68

通过kqueue,epoll,IO完成端口等解决了有效执行套接字I/O的问题.做异步文件I/O是一种后来者(除了Windows的重叠I/O和solaris早期支持posix AIO).

如果您正在寻找套接字I/O,那么最好使用上述机制之一.

因此,AIO的主​​要目的是解决异步磁盘I/O的问题.这很可能是为什么Mac OS X仅支持常规文件的AIO,而不支持套接字(因为kqueue无论如何都能做得更好).

写操作通常由内核缓存并在以后刷新.例如,当驱动器的读头碰巧通过要写入块的位置时.

但是,对于读取操作,如果您希望内核确定优先级并对读取进行排序,则AIO实际上是唯一的选择.这就是为什么内核可以(理论上)比任何用户级应用程序更好地做到这一点:

  • 内核可以看到所有磁盘I/O,而不仅仅是应用程序磁盘作业,并且可以在全局级别对它们进行排序
  • 内核(可能)知道磁盘读头的位置,并且可以选择以最佳顺序传递给它的读取作业,以便将磁头移动到最短的距离
  • 内核可以利用本机命令队列来进一步优化读取操作
  • 您可以使用lio_listio()而不是readv()为每个系统调用发出更多读取操作,尤其是如果您的读取不是(逻辑上)连续的,从而节省了一点点系统调用开销.
  • 使用AIO时,您的程序可能会稍微简单一些,因为您不需要额外的线程来阻止读取或写入调用.

也就是说,posix AIO有一个相当尴尬的界面,例如:

  • 事件回调的唯一有效和良好支持的意思是通过信号,这使得它很难在库中使用,因为它意味着使用来自进程全局信号命名空间的信号编号.如果您的操作系统不支持实时信号,那么这也意味着您必须遍历所有未完成的请求以找出实际完成的请求(例如Mac OS X的情况,而不是Linux).在多线程环境中捕获信号也会产生一些棘手的限制.您通常不会对信号处理程序内的事件做出反应,但您必须发出信号,写入管道或使用signalfd()(在Linux上).
  • lio_suspend()与select()有相同的问题,它不能很好地扩展作业数量.
  • lio_listio(),实现的工作数量相当有限,你可以传递,并且以便携方式找到这个限制并不容易.您必须调用sysconf(_SC_AIO_LISTIO_MAX),这可能会失败,在这种情况下,您可以使用AIO_LISTIO_MAX定义,这些定义不一定定义,但是您可以使用2,定义为保证支持.

至于使用posix AIO的实际应用程序,您可以看一下lighttpd(lighty),它在引入支持时也发布了性能测量.

大多数posix平台现在支持posix AIO(Linux,BSD,Solaris,AIX,tru64).Windows通过其重叠文件I/O支持它.我的理解是只有Solaris,Windows和Linux真正支持异步.文件I/O一直到驱动程序,而其他操作系统模拟异步.内核线程的I/O. Linux是例外,它在glibc中的posix AIO实现模拟用户级线程的异步操作,而其本机异步I/O接口(io_submit()等)真正异步到驱动程序,假设驱动程序支持它.

我相信在操作系统中,不支持任何fd的posix AIO,但将其限制为常规文件是相当普遍的.

  • glibc的aio_read/write实现使用userland中的线程,因此这里不使用内核线程. (5认同)

Zan*_*ynx 25

网络I/O不是AIO的优先级,因为编写POSIX网络服务器的每个人都使用基于事件的非阻塞方法.旧式的Java"数十亿阻塞线程"方法糟透了.

磁盘写入I/O已经缓冲,磁盘读取I/O可以使用posix_fadvise等函数预取到缓冲区中.这使得直接的,无缓冲的磁盘I/O成为AIO唯一有用的目的.

直接,无缓冲的I/O仅对事务数据库非常有用,并且那些倾向于编写自己的线程或进程来管理其磁盘I/O.

因此,最终使POSIX AIO处于不起任何有用目的的位置.不要使用它.

  • 我不同意.磁盘I/O往往是缓冲的,但它可以阻塞.当轮询()文件FD时,它总是报告FD是可读的,即使它将被阻止.这使得无法以均匀的方式对磁盘文件执行非阻塞操作,除非使用线程或AIO. (35认同)
  • AIO在基于事件的系统中无用是不正确的.实际上,您可以通过适当的AIO实现零拷贝网络,而不能通过基于事件的通知来调用recv().其他事情可能合谋使这主要是理论上的限制,但我认为缺乏适当的AIO(在Windows上过度重叠)是Linux中最后的一个漏洞. (13认同)
  • 从网络(NFS,Samba)文件系统读取/写入怎么样? (8认同)
  • @Matt:订单对数据报套接字并不重要.@Zan:async I/O非常适合预先缓冲实时流数据,例如媒体播放器. (2认同)

All*_*len 11

libtorrent开发人员提供了一份报告:http://blog.libtorrent.org/2012/10/asynchronous-disk-io/

  • 那将是Arvid,他也在上面回复:) (5认同)