POSIX 异步 I/O (AIO) 的现状如何?

发布于 2024-07-05 06:44:20 字数 737 浏览 13 评论 0 原文

网络上散布着一些页面,它们以不同的详细程度描述了 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”?

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

There are pages scattered around the web that describe POSIX AIO facilities in varying amounts of detail. None of them are terribly recent. It's not clear what, exactly, they're describing. For example, the "official" (?) web site for Linux kernel asynchronous I/O support here says that sockets don't work, but the "aio.h" manual pages on my Ubuntu 8.04.1 workstation all seem to imply that it works for arbitrary file descriptors. Then there's another project that seems to work at the library layer with even less documentation.

I'd like to know:

  • What is the purpose of POSIX AIO? Given that the most obvious example of an implementation I can find says it doesn't support sockets, the whole thing seems weird to me. Is it just for async disk I/O? If so, why the hyper-general API? If not, why is disk I/O the first thing that got attacked?
  • Where are there example complete POSIX AIO programs that I can look at?
  • Does anyone actually use it, for real?
  • What platforms support POSIX AIO? What parts of it do they support? Does anyone really support the implied "Any I/O to any FD" that <aio.h> seems to promise?

The other multiplexing mechanisms available to me are perfectly good, but the random fragments of information floating around out there have made me curious.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

墨小墨 2024-07-12 06:44:20

有效地进行套接字 I/O 已经通过 kqueue、epoll、IO 完成端口等解决。 执行异步文件 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 而是将其限制为常规文件是相当常见的。

Doing socket I/O efficiently has been solved with kqueue, epoll, IO completion ports and the likes. Doing asynchronous file I/O is sort of a late comer (apart from windows' overlapped I/O and solaris early support for posix AIO).

If you're looking for doing socket I/O, you're probably better off using one of the above mechanisms.

The main purpose of AIO is hence to solve the problem of asynchronous disk I/O. This is most likely why Mac OS X only supports AIO for regular files, and not sockets (since kqueue does that so much better anyway).

Write operations are typically cached by the kernel and flushed out at a later time. For instance when the read head of the drive happens to pass by the location where the block is to be written.

However, for read operations, if you want the kernel to prioritize and order your reads, AIO is really the only option. Here's why the kernal can (theoretically) do that better than any user level application:

  • The kernel sees all disk I/O, not just your applications disk jobs, and can order them at a global level
  • The kernel (may) know where the disk read head is, and can pick the read jobs you pass on to it in optimal order, to move the head the shortest distance
  • The kernel can take advantage of native command queuing to optimize your read operations further
  • You may be able to issue more read operations per system call using lio_listio() than with readv(), especially if your reads are not (logically) contiguous, saving a tiny bit of system call overhead.
  • Your program might be slightly simpler with AIO since you don't need an extra thread to block in a read or write call.

That said, posix AIO has a quite awkward interface, for instance:

  • The only efficient and well supported mean of event callbacks are via signals, which makes it hard to use in a library, since it means using signal numbers from the process-global signal namespace. If your OS doesn't support realtime signals, it also means you have to loop through all your outstanding requests to figure out which one actually finished (this is the case for Mac OS X for instance, not Linux). Catching signals in a multi-threaded environment also makes for some tricky restrictions. You can typically not react to the event inside the signal handler, but you have to raise a signal, write to a pipe or use signalfd() (on linux).
  • lio_suspend() has the same issues as select() does, it doesn't scale very well with the number of jobs.
  • lio_listio(), as implemented has fairly limited number of jobs you can pass in, and it's not trivial to find this limit in a portable way. You have to call sysconf(_SC_AIO_LISTIO_MAX), which may fail, in which case you can use the AIO_LISTIO_MAX define, which are not necessarily defined, but then you can use 2, which is defined as guaranteed to be supported.

As for real-world application using posix AIO, you could take a look at lighttpd (lighty), which also posted a performance measurement when introducing support.

Most posix platforms supports posix AIO by now (Linux, BSD, Solaris, AIX, tru64). Windows supports it via its overlapped file I/O. My understanding is that only Solaris, Windows and Linux truly supports async. file I/O all the way down to the driver, whereas the other OSes emulate the async. I/O with kernel threads. Linux being the exception, its posix AIO implementation in glibc emulates async operations with user level threads, whereas its native async I/O interface (io_submit() etc.) are truly asynchronous all the way down to the driver, assuming the driver supports it.

I believe it's fairly common among OSes to not support posix AIO for any fd, but restrict it to regular files.

巷雨优美回忆 2024-07-12 06:44:20

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

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

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

因此,最终 POSIX AIO 无法服务于任何有用的目的。 不要使用它。

Network I/O is not a priority for AIO because everyone writing POSIX network servers uses an event based, non-blocking approach. The old-style Java "billions of blocking threads" approach sucks horribly.

Disk write I/O is already buffered and disk read I/O can be prefetched into buffer using functions like posix_fadvise. That leaves direct, unbuffered disk I/O as the only useful purpose for AIO.

Direct, unbuffered I/O is only really useful for transactional databases, and those tend to write their own threads or processes to manage their disk I/O.

So, at the end that leaves POSIX AIO in the position of not serving any useful purpose. Don't use it.

薄荷→糖丶微凉 2024-07-12 06:44:20

libtorrent 开发人员对此提供了一份报告:http://blog.libtorrent.org /2012/10/异步磁盘io/

A libtorrent developer provides a report on this: http://blog.libtorrent.org/2012/10/asynchronous-disk-io/

圈圈圆圆圈圈 2024-07-12 06:44:20

有 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 之间的区别?

There is aio_write - implemented in glibc; first call of the aio_read or aio_write function spawns a number of user mode threads, aio_write or aio_read post requests to that thread, the thread does pread/pwrite and when it is finished the answer is posted back to the blocked calling thread.

Ther is also 'real' aio - supported by the kernel level (need libaio for that, see the io_submit call http://linux.die.net/man/2/io_submit ); also need O_DIRECT for that (also may not be supported by all file systems, but the major ones do support it)

see here:

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

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

Difference between POSIX AIO and libaio on Linux?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文