【问题标题】:What is the status of POSIX asynchronous I/O (AIO)?POSIX 异步 I/O (AIO) 的现状如何?
【发布时间】:2008-09-17 21:32:25
【问题描述】:

网络上散布着一些页面,它们以不同的详细程度描述了 POSIX AIO 设施。它们都不是最近的。目前尚不清楚他们到底在描述什么。例如,“官方”(?)web site for Linux kernel asynchronous I/O support here 说套接字不起作用,但我的 Ubuntu 8.04.1 工作站上的“aio.h”手册页似乎都暗示它适用于任意文件描述符。然后是 another project that seems to work at the library layer,文档更少。

我想知道:

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

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

【问题讨论】:

    标签: linux asynchronous posix bsd aio


    【解决方案1】:

    使用 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,而不仅仅是您的应用程序磁盘作业,并且可以在全局级别对它们进行排序
    • 内核(可能)知道磁盘读取磁头的位置,并且可以按照最佳顺序挑选您传递给它的读取作业,以将磁头移动最短距离
    • 内核可以利用native command queuing 进一步优化您的读取操作
    • 与使用 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),它在介绍支持时也发布了 performance measurement

    目前大多数 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 是相当普遍的,而是将其限制为常规文件。

    【讨论】:

    • 自 Win32 首次问世以来,Windows 已经有 OVERLAPPED I/O 支持磁盘文件。这一点都不新鲜。在 POSIX 上,信号命名空间不是进程全局的,而是每个线程的。信号被传递给特定的线程(或者 aio 是一个例外,无法确定?)。
    • 无法指定 AIO 将其信号传递给哪个线程。在 linux 上,它似乎大部分将它传递给发出 aio_*() 命令的线程,但并非总是如此(我发现的唯一解决方案是创建多个 signalfds)。几年前内核邮件列表上有一个 linux 补丁可以添加它,但它从未进入,它本来是 POSIX 的扩展。在 Mac OS X 上,信号似乎主要传递到主线程(根据我的经验)。我认为 POSIX 不需要特定的行为,如果需要,我很想看看规范的一部分。
    • glibc 的 aio_read/write 实现在用户态使用线程,所以这里甚至没有使用内核线程。
    • “通常”是什么意思?对于任何方法,或者在使用 AIO 时,内核都会缓存写入?似乎必须有一种方法可以让软件确定写入已成功完成;否则,将无法实现诚信和交易目标。
    • 另一个可以使用 AIO 的实例是 nginx。支持所有模式。如果您更喜欢卸载到用户态线程,您通常会发现它比直接 IO 差得多,但 Linux 原生 AIO 与直接 IO 相当。 AIO 可以显着受益的情况是严重的页面缓存压力。异步和直接 IO 之间的概念差异可以在这里看到ftp.dei.uc.pt/pub/linux/kernel/people/suparna/aio-linux.pdf
    【解决方案2】:

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

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

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

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

    【讨论】:

    • 从网络(NFS、Samba)文件系统读/写怎么样?
    • 好吧。我有几个笨拙的作家,如果我让他们去缓存,会在峰值处达到dirty_ratio,阻塞其他人。如果我只是在它们上使用直接 IO,那就太慢了。如果我只有 1 个线程,我可以自己管理,但是很难在 1 个线程中支持不同的 IO 优先级。如果 AIO 有效,AIO + CFQ 似乎真的是一个很好的组合
    • 我不同意。磁盘 I/O 往往会被缓冲,但它可能会阻塞。当 poll() 文件 FD 时,它总是报告 FD 是可读的,即使它会阻塞。这使得不可能以事件方式对磁盘文件执行非阻塞操作,除非使用线程或 AIO。
    • @Matt:顺序对于数据报套接字并不重要。 @Zan:异步 I/O 非常适合预缓冲实时流数据,例如媒体播放器。
    • AIO 在基于事件的系统中没有用是不正确的。您实际上可以使用适当的 AIO 实现零拷贝网络,而使用基于事件的 recv() 通知则无法做到这一点。其他因素可能会导致这主要是理论上的限制,但我认为缺乏适当的 AIO(Windows 上的一个 la OVERLAPPED)是 Linux 中最后的大漏洞之一。
    【解决方案3】:

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

    【讨论】:

    • 那是Arvid,他也在上面回复:)
    • 优秀的报告。很有启发性。谢谢分享。
    【解决方案4】:

    有 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

    Difference between POSIX AIO and libaio on Linux?

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-10
    • 1970-01-01
    • 2013-06-19
    • 1970-01-01
    • 2018-12-31
    • 2011-03-14
    • 1970-01-01
    • 2016-01-06
    相关资源
    最近更新 更多