非阻塞I/O真的比多线程阻塞I/O快吗?如何? [英] Is non-blocking I/O really faster than multi-threaded blocking I/O? How?

查看:120
本文介绍了非阻塞I/O真的比多线程阻塞I/O快吗?如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在网上搜索了有关阻止I/O和非阻止I/O的一些技术细节,我发现一些人指出,非阻止I/O比阻止I/O更快.例如在中该文件.

I searched the web on some technical details about blocking I/O and non blocking I/O and I found several people stating that non-blocking I/O would be faster than blocking I/O. For example in this document.

如果我使用阻塞的I/O,那么当前被阻塞的线程当然不能做任何其他事情……因为它被阻塞了.但是,一旦某个线程开始被阻塞,操作系统便可以切换到另一个线程,而不必切换回另一个线程,直到对该阻塞的线程有必要做些事情为止.因此,只要系统上还有另一个需要CPU并且没有被阻塞的线程,那么与基于事件的非阻塞方法相比,CPU空闲时间就不会更多了吗?

If I use blocking I/O, then of course the thread that is currently blocked can't do anything else... Because it's blocked. But as soon as a thread starts being blocked, the OS can switch to another thread and not switch back until there is something to do for the blocked thread. So as long as there is another thread on the system that needs CPU and is not blocked, there should not be any more CPU idle time compared to an event based non-blocking approach, is there?

除了减少CPU空闲时间外,我还看到了另一个选择,可以增加计算机在给定时间范围内可以执行的任务数量:减少切换线程带来的开销.但是,如何做到这一点呢?开销足够大以显示可测量的效果吗?这是我如何描述其工作原理的想法:

Besides reducing the time the CPU is idle I see one more option to increase the number of tasks a computer can perform in a given time frame: Reduce the overhead introduced by switching threads. But how can this be done? And is the overhead large enough to show measurable effects? Here is an idea on how I can picture it working:

  1. 要加载文件的内容,应用程序将此任务委托给基于事件的I/O框架,并传递回调函数和文件名
  2. 事件框架委托给操作系统,该操作系统对硬盘的DMA控制器进行编程,以将文件直接写到内存中
  3. 事件框架允许进一步的代码运行.
  4. 完成磁盘到内存副本后,DMA控制器会引起中断.
  5. 操作系统的中断处理程序通知基于事件的I/O框架有关文件已完全加载到内存中的信息.它是如何做到的?使用信号?
  6. 事件i/o框架中当前运行的代码完成.
  7. 基于事件的I/o框架检查其队列,并查看步骤5中的操作系统消息,并执行在步骤1中获得的回调.

它是如何工作的?如果没有,它如何工作?这意味着事件系统可以工作而无需显式地触摸堆栈(例如,真正的调度程序需要在切换线程时备份堆栈并将另一个线程的堆栈复制到内存中)?这实际上节省了多少时间?还有更多吗?

Is that how it works? If it does not, how does it work? That means that the event system can work without ever having the need to explicitly touch the stack (such as a real scheduler that would need to backup the stack and copy the stack of another thread into memory while switching threads)? How much time does this actually save? Is there more to it?

推荐答案

非阻塞或异步I/O的最大优点是线程可以并行继续工作.当然,您也可以使用其他线程来实现.正如您所说的那样,为了获得最佳的总体(系统)性能,我认为使用异步I/O而不是使用多个线程会更好(这样可以减少线程切换).

The biggest advantage of nonblocking or asynchronous I/O is that your thread can continue its work in parallel. Of course you can achieve this also using an additional thread. As you stated for best overall (system) performance I guess it would be better to use asynchronous I/O and not multiple threads (so reducing thread switching).

让我们看一下将处理1000个并行连接的客户端的网络服务器程序的可能实现:

Let's look at possible implementations of a network server program that shall handle 1000 clients connected in parallel:

  1. 每个连接一个线程(可以是阻塞的I/O,也可以是非阻塞的I/O).
    每个线程都需要内存资源(也是内核内存!),这是一个缺点.而且每个额外的线程都意味着调度程序需要做更多的工作.
  2. 一个线程用于所有连接.
    因为我们线程较少,所以这会负担系统的负载.但这也会阻止您使用计算机的全部性能,因为您可能最终会将一个处理器驱动到100%,并让所有其他处理器闲置.
  3. 几个线程,每个线程处理一些连接.
    因为线程较少,所以这会负担系统负载.它可以使用所有可用的处理器.在Windows上,支持此方法线程池API .
  1. One thread per connection (can be blocking I/O, but can also be non-blocking I/O).
    Each thread requires memory resources (also kernel memory!), that is a disadvantage. And every additional thread means more work for the scheduler.
  2. One thread for all connections.
    This takes load from the system because we have fewer threads. But it also prevents you from using the full performance of your machine, because you might end up driving one processor to 100% and letting all other processors idle around.
  3. A few threads where each thread handles some of the connections.
    This takes load from the system because there are fewer threads. And it can use all available processors. On Windows this approach is supported by Thread Pool API.

当然,拥有更多线程本身不是问题.正如您可能已经认识到的那样,我选择了大量的连接/线程.我怀疑如果我们只谈论十几个线程,您是否会发现这三种可能的实现之间有任何区别(这也是Raymond Chen在MSDN博客文章

Of course having more threads is not per se a problem. As you might have recognized that I chose quite a high number of connections/threads. I doubt that you'll see any difference between the three possible implementations if we are talking about only a dozen threads (this is also what Raymond Chen suggests on the MSDN blog post Does Windows have a limit of 2000 threads per process?).

在Windows上使用无缓冲文件I/O 表示写操作的大小必须是页面大小的倍数.我尚未对其进行测试,但听起来这也可能对缓冲的同步和异步写入产生积极的影响.

On Windows using unbuffered file I/O means that writes must be of a size which is a multiple of the page size. I have not tested it, but it sounds like this could also affect write performance positively for buffered synchronous and asynchronous writes.

您描述的步骤1至7很好地说明了它是如何工作的.在Windows上,操作系统将使用事件或回调通知您有关异步I/O(具有OVERLAPPED结构的WriteFile)的完成.仅当您的代码在bAlertable设置为true的情况下调用WaitForMultipleObjectsEx时,才会调用回调函数.

The steps 1 to 7 you describe give a good idea of how it works. On Windows the operating system will inform you about completion of an asynchronous I/O (WriteFile with OVERLAPPED structure) using an event or a callback. Callback functions will only be called for example when your code calls WaitForMultipleObjectsEx with bAlertable set to true.

更多网上阅读内容:

  • Multiple Threads in the User Interface on MSDN, also shortly handling the cost of creating threads
  • Section Threads and Thread Pools says "Although threads are relatively easy to create and use, the operating system allocates a significant amount of time and other resources to manage them."
  • CreateThread documentation on MSDN says "However, your application will have better performance if you create one thread per processor and build queues of requests for which the application maintains the context information.".
  • Old article Why Too Many Threads Hurts Performance, and What to do About It

这篇关于非阻塞I/O真的比多线程阻塞I/O快吗?如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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