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

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

问题描述

考虑是CPU密集型的应用程序,而且还具有高性能的I / O需求。

我的Linux文件I / O比较Windows和我看不到epoll的将如何帮助一个Linux程序都没有。内核会告诉我该文件描述符是准备好读,但我还是要呼叫阻塞的read()来获得我的数据,如果我想读兆,这是pretty明确表示,这将阻止。

在Windows上,我可以创建重叠的一套文件句柄,然后使用非阻塞I / O,并获得通知的I / O完成时,并从该完成的功能使用的数据。我需要花任何应用程序级的挂钟时间等待数据,这意味着我可以precisely调整我的线程数我的内核数量,并获得100%的提高CPU使用效率。

如果我要模仿异步I /于Linux操作系统,那么我不得不分配线程的一些数量要做到这一点,而这些线程会花费一点点时间做CPU的事情,很多时候阻断我/ O,再加上会有开销从那些线程的消息传递/。因此,我将在过认购或下利用我的CPU核心。

我看着mmap()的+的madvise()(WILLNEED)作为穷人的异步I / O,但它仍然没有得到所有的方式出现,因为当它这样做,我不能得到一个通知 - - 我有猜如果我猜错了我将结束封锁内存访问,等待数据来自磁盘

的Linux似乎有异步I /在io_submit 0的开始,它似乎也有一个用户空间的POSIX AIO实现,但它已经这样了一段时间,我知道没有人谁也证实了这些的系统为关键的,高性能的应用

在Windows模型的工作原理大致是这样的:


  1. 问题异步操作。

  2. 领带异步操作到一个特定的I / O完成端口。

  3. 等待操​​作,以完成该端口上

  4. 当I / O完成,线程等待的端口疏导,并返回到挂起的I / O操作的参考。

1/2的步骤通常完成一个单一的东西。步骤3/4通常与工作线程,不(一定)相同的线程问题的I / O池完成的。这种模式有点类似于通过的boost :: ASIO提供的模型,除了升压:: ASIO实际上不会给你异步的基于块(磁盘)的I / O。

在Linux的epoll的区别在于,在步骤4中,没有I / O还没有发生的事情 - 它吊第1步来第4步,这是倒退如果你知道你需要什么已经在

已经设定了大量的嵌入式,桌面和服务器操作系统的,我可以说,异步I这种模式/ O是某些种类的节目很自然的。这也是非常高吞吐量和低开销。我认为这是Linux的I / O模型的剩余真正的缺点之一,在API级别。


解决方案

真正的答案,这是间接由彼得赵明福指出,基于io_setup()和io_submit()。
具体地,由Peter指示的aio_函数是基于线程glibc的用户级仿真,这不是一种有效的实现的一部分。
真正的答案是:

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

请注意,该男子页,日期为2012-08说,此实现尚未成熟的地步,它可以代替glibc的用户空间模拟:

<一个href=\"http://man7.org/linux/man-pages/man7/aio.7.html\">http://man7.org/linux/man-pages/man7/aio.7.html


  

此实现尚未成熟的地步了POSIX
  AIO实现可以使用内核完全重新实现
  系统调用。


因此​​,根据最新的内核文档可以找我,Linux的还没有一个成熟的,基于内核的异步I / O模型。而且,如果我假设记录模式实际上是成熟的,但它仍然不支持部分的I / O的recv()与读的感觉()。

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

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.

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.

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.

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 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.

The Windows model works roughly like this:

  1. Issue an asynchronous operation.
  2. Tie the asynchronous operation to a particular I/O completion port.
  3. Wait on operations to complete on that port
  4. When the I/O is complete, the thread waiting on the port unblocks, and returns a reference to the pending I/O operation.

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.

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.

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.

解决方案

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)

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

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

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天全站免登陆