linux - linux上的缓冲异步文件I/O

标签 linux asynchronous io linux-kernel aio

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

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

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

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

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

最佳答案

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

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

直到最近,才能获得由完成的异步操作发出的 epoll 信号是另一个问题,但与此同时,通过 eventfd 可以正常工作。

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

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

关于linux - linux上的缓冲异步文件I/O,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5664105/

相关文章:

linux - 复制文件并保留目录结构

c - 从socket读取到buffer,再从buffer逐行读取实现http语言

c - semop 调用中 EIDRM 和 EINVAL errno 之间的区别

c - 将.txt文件字符串添加到c中数组中的各个位置

json - 如何在以下输出中获取过去 7 天的信息

javascript - 如何在 Javascript/Node 中的异步函数上调用 Await 后超时

node.js - 在node.js中同步调用

c# - 如何在 C# 中异步提取 zip 文件以不阻塞 UI?

haskell - 如何在haskell中输入整数? (在控制台输入)

io - 从 Erlang 读取一个字符输入,而不需要在提示符下按下 Return 键