96

网络上散布着一些页面,它们以不同的详细程度描述了 POSIX AIO 设施。它们都不是最近的。目前尚不清楚他们到底在描述什么。例如,此处用于 Linux 内核异步 I/O 支持的“官方”(?)网站说套接字不起作用,但我的 Ubuntu 8.04.1 工作站上的“aio.h”手册页似乎都暗示了这一点它适用于任意文件描述符。然后还有另一个项目似乎在库层工作,文档更少。

我想知道:

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

我可以使用的其他多路复用机制非常好,但是那里漂浮的随机信息片段让我很好奇。

4

4 回答 4

72

使用 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,而不仅仅是您的应用程序磁盘作业,并且可以在全局级别对它们进行排序
  • 内核(可能)知道磁盘读取头在哪里,并且可以按照最佳顺序选择您传递给它的读取作业,以将磁头移动最短距离
  • 内核可以利用本机命令队列来进一步优化您的读取操作
  • 与使用 readv() 相比,使用 lio_listio() 可以为每个系统调用发出更多的读取操作,特别是如果您的读取不是(逻辑上)连续的,从而节省了一点系统调用开销。
  • 使用 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 是相当普遍的,但将其限制为常规文件。

于 2011-03-15T04:30:59.297 回答
30

网络 I/O 不是 AIO 的优先事项,因为每个编写 POSIX 网络服务器的人都使用基于事件的非阻塞方法。老式的 Java “数十亿个阻塞线程”方法非常糟糕。

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

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

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

于 2008-09-17T23:15:51.280 回答
12

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

于 2012-10-26T15:29:36.813 回答
2

有 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

http://linux.die.net/man/2/io_submit

Linux 上 POSIX AIO 和 libaio 的区别?

于 2014-10-27T08:40:53.577 回答