Linux 上真的没有异步块 I/O 吗? [英] Is there really no asynchronous block I/O on Linux?

查看:26
本文介绍了Linux 上真的没有异步块 I/O 吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一个受 CPU 限制但也具有高性能 I/O 要求的应用程序.

Consider an application that is CPU bound, but also has high-performance I/O requirements.

我正在将 Linux 文件 I/O 与 Windows 进行比较,我完全看不出 epoll 将如何帮助 Linux 程序.内核会告诉我文件描述符准备好读取",但我仍然需要调用阻塞 read() 来获取我的数据,如果我想读取兆字节,很明显它会阻塞.

I'm comparing Linux file I/O to Windows, and I can't see how epoll will help a Linux program at all. The kernel will tell me that the file descriptor is "ready for reading," but I still have to call blocking read() to get my data, and if I want to read megabytes, it's pretty clear that that will block.

在 Windows 上,我可以创建一个设置了 OVERLAPPED 的文件句柄,然后使用非阻塞 I/O,并在 I/O 完成时得到通知,并使用来自该完成函数的数据.我不需要花费应用程序级挂钟时间来等待数据,这意味着我可以根据我的内核数精确调整线程数,并获得 100% 的 CPU 利用率.

On Windows, I can create a file handle with OVERLAPPED set, and then use non-blocking I/O, and get notified when the I/O completes, and use the data from that completion function. I need to spend no application-level wall-clock time waiting for data, which means I can precisely tune my number of threads to my number of cores, and get 100% efficient CPU utilization.

如果我必须在 Linux 上模拟异步 I/O,那么我必须分配一些线程来执行此操作,这些线程将花费一点时间来处理 CPU 的事情,并且大量时间为我阻塞/O,加上与这些线程之间的消息传递会产生开销.因此,我要么过度订阅,要么未充分利用我的 CPU 内核.

If I have to emulate asynchronous I/O on Linux, then I have to allocate some number of threads to do this, and those threads will spend a little bit of time doing CPU things, and a lot of time blocking for I/O, plus there will be overhead in the messaging to/from those threads. Thus, I will either over-subscribe or under-utilize my CPU cores.

我将 mmap() + madvise() (WILLNEED) 视为穷人的异步 I/O",但它仍然没有完全到位,因为我无法在完成后收到通知 -- 我必须猜测",如果我猜测错误",我最终会阻塞内存访问,等待数据来自磁盘.

I looked at mmap() + madvise() (WILLNEED) as a "poor man's async I/O" but it still doesn't get all the way there, because I can't get a notification when it's done -- I have to "guess" and if I guess "wrong" I will end up blocking on memory access, waiting for data to come from disk.

Linux 似乎在 io_submit 中有异步 I/O 的启动,而且它似乎也有用户空间 POSIX aio 实现,但这种情况已经有一段时间了,我知道没有人会为这些提供担保用于关键、高性能应用的系统.

Linux seems to have the starts of async I/O in io_submit, and it seems to also have a user-space POSIX aio implementation, but it's been that way for a while, and I know of nobody who would vouch for these systems for critical, high-performance applications.

Windows 模型的工作原理大致如下:

The Windows model works roughly like this:

  1. 发出异步操作.
  2. 将异步操作绑定到特定的 I/O 完成端口.
  3. 等待该端口上的操作完成
  4. 当 I/O 完成时,在端口上等待的线程解除阻塞,并返回对挂起的 I/O 操作的引用.

第 1/2 步通常作为一件事完成.步骤 3/4 通常使用工作线程池完成,而不是(必须)与发出 I/O 的线程相同.这个模型有点类似于 boost::asio 提供的模型,除了 boost::asio 实际上并没有给你基于块(磁盘)的异步 I/O.

Steps 1/2 are typically done as a single thing. Steps 3/4 are typically done with a pool of worker threads, not (necessarily) the same thread as issues the I/O. This model is somewhat similar to the model provided by boost::asio, except boost::asio doesn't actually give you asynchronous block-based (disk) I/O.

Linux 中 epoll 的不同之处在于,在第 4 步中,还没有发生 I/O——它会将第 1 步提升到第 4 步之后,如果您已经确切地知道自己需要什么,那就是倒退".

The difference to epoll in Linux is that in step 4, no I/O has yet happened -- it hoists step 1 to come after step 4, which is "backwards" if you know exactly what you need already.

在编写了大量嵌入式、桌面和服务器操作系统之后,我可以说这种异步 I/O 模型对于某些类型的程序来说非常自然.它也是非常高吞吐量和低开销的.我认为这是 Linux I/O 模型在 API 级别上剩余的真正缺点之一.

Having programmed a large number of embedded, desktop, and server operating systems, I can say that this model of asynchronous I/O is very natural for certain kinds of programs. It is also very high-throughput and low-overhead. I think this is one of the remaining real shortcomings of the Linux I/O model, at the API level.

推荐答案

Peter Teoh 间接指出的真正答案是基于 io_setup() 和 io_submit().具体来说,Peter所指的aio_"函数是基于线程的glibc用户级仿真的一部分,并不是一个高效的实现.真正的答案在:

The real answer, which was indirectly pointed to by Peter Teoh, is based on io_setup() and io_submit(). Specifically, the "aio_" functions indicated by Peter are part of the glibc user-level emulation based on threads, which is not an efficient implementation. The real answer is in:

io_submit(2)
io_setup(2)
io_cancel(2)
io_destroy(2)
io_getevents(2)

请注意,日期为 2012 年 8 月的手册页表示此实现尚未成熟到可以取代 glibc 用户空间模拟的程度:

Note that the man page, dated 2012-08, says that this implementation has not yet matured to the point where it can replace the glibc user-space emulation:

http://man7.org/linux/man-pages/man7/aio.7.html

这个实现还没有成熟到 POSIXAIO 实现可以使用内核完全重新实现系统调用.

this implementation hasn't yet matured to the point where the POSIX AIO implementation can be completely reimplemented using the kernel system calls.

所以,根据我能找到的最新内核文档,Linux 还没有一个成熟的、基于内核的异步 I/O 模型.而且,如果我假设文档模型实际上已经成熟,它仍然不支持 recv() 与 read() 意义上的部分 I/O.

So, according to the latest kernel documentation I can find, Linux does not yet have a mature, kernel-based asynchronous I/O model. And, if I assume that the documented model is actually mature, it still doesn't support partial I/O in the sense of recv() vs read().

这篇关于Linux 上真的没有异步块 I/O 吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆