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


93

网上散布着许多页面,这些页面以不同的细节描述了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” 吗?

我可以使用的其他多路复用机制非常好,但是随处可见的随机信息碎片使我感到好奇。

Answers:


27

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

磁盘写I / O已被缓冲,可以使用posix_fadvise之类的功能将磁盘读I / O预取到缓冲区中。这将直接的,无缓冲的磁盘I / O留作AIO的唯一有用目的。

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

因此,最后使POSIX AIO失去了任何有用的作用。不要使用它。


8
从网络(NFS,Samba)文件系统读取/写入怎么样?
Alex B

1
好。我有几个笨拙的作家,如果我让他们去缓存,它们会在高峰时达到dirty_ratio,从而阻塞其他所有人。如果仅在它们上使用直接IO,则速度太慢。如果我只有1个线程,则可以自己管理,但是很难在1个步骤中支持不同的IO优先级。如果AIO有效,AIO + CFQ似乎真的是一个很好的组合
n-alexander 2010年

37
我不同意。磁盘I / O倾向于缓冲,但可能会阻塞。在轮询文件FD时,它始终报告FD是可读的,即使它会阻塞。这使得不可能以事件的方式对磁盘文件执行非阻塞操作,除非使用线程或AIO。
Hongli

2
@Matt:顺序对于数据报套接字并不重要。@赞:异步I / O非常适合预缓冲实时流数据,例如媒体播放器。
Ben Voigt

13
在基于事件的系统中,AIO并非毫无用处。实际上,您可以使用适当的AIO进行零复制网络,而对于基于事件的recv()通知则无法实现。其他因素可能合起来使这主要是理论上的限制,但是我认为缺少适当的AIO(在Windows上是OVERLAPPED)是Linux最后的大漏洞之一。
乔恩·瓦特

69

通过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()可能比使用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一直到驱动程序,而其他OS则模拟异步。具有内核线程的I / O。Linux是个例外,它在glibc中的posix AIO实现模拟了用户级线程的异步操作,而其本机异步I / O接口(io_submit()等)一直到驱动程序都是真正异步的,前提是驱动程序支持它。

我相信在OS中,不为任何fd支持posix AIO而是将其限制为常规文件是相当普遍的。


自Win32首次问世以来,Windows就已经具有支持I / O的OVERLAPPED I / O。这根本不是新的。在POSIX上,信号名称空间不是进程全局的,而是每个线程的。信号被传递到特定的线程(或者是一个例外,无法确定吗?)。
Ben Voigt

1
无法指定AIO将信号发送到哪个线程。在linux上,它似乎通常将其传递给发出aio _ *()命令的线程,但并非总是如此(我发现的唯一解决方案是创建多个signalfds)。几年前,内核邮件列表上有一个Linux补丁程序可以添加此功能,但它从来没有加入过,它本来是POSIX的扩展。在Mac OS X上,信号似乎主要传递到主线程(以我的经验)。我认为POSIX不需要特定的行为,如果需要,我希望看到规范的一部分。
阿维德(Arvid)

5
glibc的aio_read / write实现使用userland中的线程,因此这里甚至不使用内核线程。
Marenz 2011年

“通常”通常是什么意思?内核会为任何方法或使用AIO缓存写操作。似乎必须有一种方法可以使软件确定写入已成功完成;否则,诚信和交易目标将无法实现。
MikeB 2013年

您可以使用AIO的另一个实时示例是nginx。支持所有模式。如果您希望分载到用户级线程,通常会发现它比直接IO差很多,但是Linux本机AIO与直接IO相当。AIO可以带来实质性好处的情况是严重的页面缓存压力。异步和直接IO之间的概念差异可以在这里ftp.dei.uc.pt/pub/linux/kernel/people/suparna/aio-linux.pdf
wick


2

有aio_write-在glibc中实现;第一次调用aio_read或aio_write函数会产生许多用户模式线程,对该线程发出aio_write或aio_read post请求,该线程会进行pread / pwrite操作,并在完成后将答案回发到阻塞的调用线程中。

这也是“真正的” aio-内核级别支持(为此需要libaio,请参见io_submit调用http://linux.die.net/man/2/io_submit);为此也需要O_DIRECT(可能并非所有文件系统都支持O_DIRECT,但是主要的文件系统都支持它)

看这里:

http://lse.sourceforge.net/io/aio.html

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

POSIX AIO和Linux上的libaio之间的区别?


的许多缺陷aio_write已在stackoverflow.com/a/5307557/13564
Glyph
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.