在linux上缓冲异步文件I/O.

Mar*_*enz 31 linux io asynchronous aio linux-kernel

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

POSIX glibc实现使用userland中的线程.

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

我发现了许多允许异步I/O的其他想法,概念和补丁,尽管其中大多数都是在3年以上的文章中.在今天的内核中真正可用的是什么呢?我已经阅读过有关servlet,acalls,内核线程的内容以及我现在甚至都不记得的更多内容.

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

Dam*_*mon 35

除非你想编写自己的IO线程池,否则glibc实现是一个可接受的解决方案.对于完全在用户区运行的东西,它实际上效果非常好.

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

能够epoll通过完成的异步操作发出信号直到最近还是另一个问题,但同时这个工作非常好eventfd.

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

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

  • 在我看来,最干净的解决方案是完全删除阻塞IO并使所有IO异步.然后需要在库中重新实现"通常的"阻塞IO. (3认同)

Pet*_*son 5

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

    UNIX 环境中的高级编程

另外两卷也是史蒂文斯的,是他的Unix 网络编程集的前两卷:

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

我无法想象没有这三本基础书籍;当我发现有人没有听说过他们时,我会目瞪口呆。

史蒂文的更多书籍同样珍贵:

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