31

我正在寻找在 linux 上进行异步文件 I/O 的最有效方法。

POSIX glibc 实现在用户空间中使用线程。

本机 aio 内核 api 仅适用于无缓冲操作,存在用于内核添加对缓冲操作的支持的补丁,但这些补丁已经超过 3 年了,似乎没有人关心将它们集成到主线中。

我发现了许多允许异步 I/O 的其他想法、概念、补丁,尽管其中大部分都在 3 年以上的文章中。所有这些在今天的内核中真正可用的是什么?我读过关于 servlet、acall、内核线程的东西以及更多我现在不记得的东西。

在当今内核中进行缓冲异步文件输入/输出的最有效方法是什么?

4

4 回答 4

34

除非您想编写自己的 IO 线程池,否则 glibc 实现是一个可以接受的解决方案。对于完全在用户空间中运行的东西,它实际上工作得非常好。

根据我的经验,内核实现根本不适用于缓冲 IO(尽管我见过其他人说相反的说法!)。如果您想通过 DMA 读取大量数据,这很好,但如果您打算利用缓冲区高速缓存,这当然会浪费大量时间。
另请注意,内核 AIO 调用实际上可能会阻塞。有一个大小有限的命令缓冲区,大的读取被分解成几个较小的。一旦队列满了,异步命令就会同步运行。惊喜。一两年前我遇到过这个问题,但找不到解释。四处询问给了我“是的,当然,这就是它的工作原理”的答案。
据我了解,尽管多年来似乎有几种可行的解决方案,但支持缓冲 aio 的“官方”兴趣也不是很大。我读过的一些论点是“你无论如何都不想使用缓冲区”和“没有人需要那个”和“大多数人甚至不使用 epoll”。所以,嗯……嗯。

直到最近,能够epoll通过已完成的异步操作获得信号是另一个问题,但与此同时,通过eventfd.

请注意,glibc 实现实际上会在内部按需生成__aio_enqueue_request线程。这可能没什么大不了的,因为生成线程不再那么昂贵,但应该意识到这一点。如果您对启动异步操作的理解是“立即返回”,那么该假设可能不正确,因为它可能首先产生了一些线程。

编辑
作为旁注,在 Windows 下存在与 glibc AIO 实现中的情况非常相似的情况,其中“立即返回”排队异步操作的假设不正确。
如果您要读取的所有数据都在缓冲区缓存中,Windows 将决定改为同步运行请求,因为无论如何它都会立即完成。这是有据可查的,当然听起来也很棒。除非有几兆字节要复制,或者另一个线程有页面错误或同时执行 IO(因此竞争锁)“立即”可能是一个令人惊讶的长时间——我已经看到“立即”时间为 2 -5 毫秒。这在大多数情况下都没有问题,但例如在 16.66 毫秒帧时间的约束下,您可能不想冒险在随机时间阻塞 5 毫秒。因此,“可以从我的渲染线程执行异步 IO 没有问题,因为异步不会阻塞”的天真假设是有缺陷的。

于 2011-04-14T14:18:55.927 回答
4

材料看起来很旧——嗯,它旧——因为它已经存在很长时间了,虽然绝不是微不足道的,但很好理解。一个你可以举起的解决方案发表在 W. Richard Stevens 的精湛而无与伦比的书中(阅读“圣经”)。这本书是清晰、简洁、完整的稀世珍宝:每一页都赋予了真实而直接的价值:

    UNIX 环境中的高级编程

史蒂文斯的另外两本书是他的Unix 网络编程合集的前两卷:

   第 1 卷:套接字网络 API (与 Fenner 和 Rudoff 一起)
   第 2 卷:进程间通信

我无法想象没有这三本基础书籍;当我找到一个没听说过他们的人时,我傻眼了。

还有更多史蒂文的书,同样珍贵:

   TCP/IP 图解,卷。1:协议

于 2011-04-14T16:19:43.687 回答
2

我不认为异步文件 I/O 的 Linux 内核实现真的可用,除非你也使用 O_DIRECT,抱歉。

这里有更多关于世界当前状态的信息:https ://github.com/littledan/linux-aio 。它由曾经在 Google 工作的人在 2012 年更新。

于 2013-02-08T03:58:22.910 回答
2

(2021) 如果您的 Linux 内核足够新(至少 5.1,但更新的内核带来了改进),那么io_uring将是“进行异步文件输入/输出的最有效方式” *。这适用于缓冲和直接 I/O!

在 Kernel Recipes 2019 视频“通过 io_uring 实现更快的 IO”中,io_uring作者Jens Axboe 通过io_uring完成几乎一半的同步缓冲 I/O 时间演示了缓冲 I/O。正如@Marenz 所指出的,除非您想要用户空间线程io_uring是执行缓冲异步 I/O 的唯一方法,因为Linux AIO(又名libaio/ io_submit())无法始终执行缓冲异步 I/O ...

此外,在“现代存储速度非常快”一文中。Glauber Costa 演示了io_uringio_uring与在 Optane 设备上使用异步缓冲 I/O相比,谨慎使用异步直接 I/O 可以提高吞吐量。它要求 Glauber 具有用户空间预读实现(没有它缓冲 I/O 显然是赢家),但改进令人印象深刻。


*这个答案的上下文显然与存储有关(在提到缓冲这个词之后)。因为网络 I/Oio_uring在后来的内核中稳步改进,以至于它可以与类似的东西进行交易epoll(),如果它继续下去,总有一天它会在所有情况下都相等或更好。

于 2021-04-11T06:19:06.577 回答