非阻塞I / O是否比多线程阻塞I / O更快?(Is non-blocking I/O really faster than multi-threaded blocking I/O? How?)

我在网络上搜索了关于阻塞I / O和非阻塞I / O的一些技术细节,我发现几个人表示非阻塞I / O将比阻塞I / O更快。 例如在本文档中 。

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

除了减少CPU空闲时间外,还有一个选项可以增加计算机在给定时间范围内执行的任务数量:减少切换线程引入的开销。 但是怎么做呢? 是足够大的足够显示可衡量的效果的头顶吗? 这是一个关于如何使图片工作的想法:

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

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


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.

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?

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. To load the contents of a file, an application delegates this task to an event-based i/o framework, passing a callback function along with a filename
  2. The event framework delegates to the operating system, which programs a DMA controller of the hard disk to write the file directly to memory
  3. The event framework allows further code to run.
  4. Upon completion of the disk-to-memory copy, the DMA controller causes an interrupt.
  5. The operating system's interrupt handler notifies the event-based i/o framework about the file being completely loaded into memory. How does it do that? Using a signal??
  6. The code that is currently run within the event i/o framework finishes.
  7. The event-based i/o framework checks its queue and sees the operating system's message from step 5 and executes the callback it got in step 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?


原文:https://stackoverflow.com/questions/8546273
2021-05-17 15:05

满意答案

非阻塞或异步I / O的最大优点是您的线程可以继续并行工作。 当然你也可以使用额外的线程实现这一点。 正如你所说的最好的整体(系统)性能我猜最好使用异步I / O而不是多线程(因此减少线程切换)。

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

  1. 每个连接一个线程(可以阻塞I / O,但也可以是非阻塞I / O)。
    每个线程需要内存资源(也是内核内存!),这是一个缺点。 并且每个额外的线程意味着更多的调度器的工作。
  2. 所有连接的一个线程。
    这需要系统的负载,因为我们有更少的线程。 但它也阻止您使用机器的全部性能,因为您可能最终将一个处理器推向100%,并让所有其他处理器闲置。
  3. 每个线程处理一些连接的几个线程。
    这需要系统加载,因为线程较少。 它可以使用所有可用的处理器。 在Windows上,此方法由Thread Pool API支持。

当然,有更多的线程本身不是一个问题。 你可能已经认识到我选择了相当多的连接/线程。 我怀疑,如果我们只讨论十几个线程,这三个可能的实现之间将会有任何区别(这也是Raymond Chen在MSDN博客文章上提到的Windows Windows每个进程的限制为2000个 )。

在Windows上使用无缓冲的文件I / O意味着写入的大小必须是页面大小的倍数。 我还没有测试过,但是听起来这样也可能会对缓冲同步和异步写入产生积极的影响。

你描述的步骤1到7给出了它如何工作的好主意。 在Windows上,操作系统将使用事件或回调通知您有关异步I / O(具有OVERLAPPED结构的WriteFile )的完成。 回调函数只会被调用,例如当你的代码调用WaitForMultipleObjectsEx其中bAlertable设置为true

网上更多阅读:

  • MSDN上的用户界面中的多个线程也很快处理创建线程的成本
  • 部分线程和线程池说“虽然线程相对容易创建和使用,但是操作系统会分配大量的时间和其他资源来进行管理。”
  • MSDN上的CreateThread文档说:“但是,如果您为每个处理器创建一个线程并构建应用程序维护上下文信息的请求队列,那么您的应用程序将具有更好的性能。
  • 旧文章为什么太多线程会伤害性能,以及如何处理

The biggest advantage of nonblocking or asynchronous I/O is that your thread can continue it's 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).

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

  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.

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

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.

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.

Some more reading on the web:

相关问答

更多

每个请求模型的线程能否比非阻塞I / O更快?(Can the thread per request model be faster than non-blocking I/O?)

不是在我看来。 如果两种模式都得到很好的实施(这是一个大的要求),我认为NIO的概念应该占上风。 计算机的核心是核心。 不管你做什么,你都不能使你的应用程序并行化,而不是你的核心。 即如果你有一个4核心机器,你一次只能做4件事(我在这里详述了一些细节,但这足以说明这个论点)。 扩展这个想法,如果你有比线程更多的线程,你就会浪费。 这种浪费有两种形式。 首先是额外的线程本身的开销。 其次是在线程之间切换的时间。 两者可能都很小,但他们在那里。 理想情况下,每个核心都有一个线程,每个线程在核心上的运行...

如何使这个非阻塞服务器多线程?(How do I make this non-blocking server multi-threaded?)

我的解决方案i Netty和Executor创建了ThreadPool。 您只需添加处理程序do Netty的管道,该管道将执行程序称为ChannelBuffer作为参数。 每个客户端请求将由单独的线程处理。 看看这些例子 My solution i Netty and Executor which creates ThreadPool. You simply add handler do Netty's pipeline, which call executor witch ChannelBuf...

Node.js中的非阻塞或异步I / O是什么?(What is non-blocking or asynchronous I/O in Node.js?)

同步与异步 同步执行通常是指按顺序执行的代码。 异步执行是指不按照代码中出现的顺序运行的执行。 在以下示例中,同步操作会使警报依次触发。 在异步操作中,当alert(2)似乎执行第二个时,它不会。 同步:1,2,3 alert(1); alert(2); alert(3); 异步:1,3,2 alert(1); setTimeout(() => alert(2), 0); alert(3); 阻止vs非阻塞 阻塞是指阻止进一步执行的操作,直到该操作完成。 非阻塞是指不阻止执行的代码。 在给...

如何通过Node.js中的线程池处理阻塞I / O?(how is blocking I/O handled via the threadpool in Node.js?)

节点js进程由运行事件循环的主线程和工作线程组成。 编码器无法明确地使用这些工作线程。 现在,当您从代码中执行系统调用(即调用内部执行系统调用的节点js函数)时,根据这些是阻塞(例如文件I / O)还是非阻塞(例如套接字I / O),作业可能会被发送到工作线程。 但是,始终在事件循环中注册回调。 因此,如果工作者完成处理作业,它会通知事件循环,因此从编码器的角度来看,操作是异步的。 现在,CPU是多线程还是单线程并不重要。 那是因为从磁盘读取需要一些时间,在此期间CPU不忙于该线程。 操作系统知道...

JS在OS级别使用非阻塞I / O来支持AJAX吗?(Do JS use Non blocking I/O at OS level to support AJAX?)

是的,浏览器引擎正在为Ajax进行非阻塞I / O调用(当您执行非阻塞的ajax调用时)。 浏览器可以通过多种不同的方式实现ajax网络。 我们唯一确定的是ajax i / o请求没有阻止javascript线程。 而且,每个浏览器都可以自由地实现它,只要它们不阻止JS执行线程和在ajax调用期间保持浏览器功能所需的任何其他线程。 在浏览器内部,它可能是使用一个单独的OS线程在该线程上以阻塞方式运行ajax调用,它可能在单独的线程上使用非阻塞i / o,它可能使用非阻止javascript解释器线...

NodeJs中单线程和非阻塞I / O操作有什么区别?(What is the difference between single thread and non-blocking I/O operation in NodeJs?)

我会尽力解释。 单线程意味着Node.js Javascript运行时 - 在特定的时间点 - 只执行其加载的所有代码中的一段代码。 实际上,它从某个地方开始,并通过所有指令(调用堆栈)完成,直到完成。 在执行代码时,没有什么可以中断这个过程,所有的I / O都必须等待。 值得庆幸的是,大多数调用堆栈都比较短,我们在Node.js中做的很多事情比“CPU”更重要的是“簿记”类型。 尽管是单线程的,但任何需要很长时间的指令都会成为系统响应的一个巨大问题。 运行时一次只能做一件事,所以一切都必须等到该...

什么python库用于OSX上的非阻塞音频I / O?(What python library to use for non-blocking audio I/O on OSX?)

几天前,我向pyAudio提交了一个补丁,可以在那里启用非阻塞音频I / O. 从版本0.2.7开始,补丁就在。现在PyAudio正式支持非阻塞I / O. A few days ago, I submitted a patch to pyAudio that enables non blocking audio I/O there. As of Version 0.2.7, the patch is in. Now non-blocking I/O is officially supported...

非阻塞I / O是否比多线程阻塞I / O更快?(Is non-blocking I/O really faster than multi-threaded blocking I/O? How?)

非阻塞或异步I / O的最大优点是您的线程可以继续并行工作。 当然你也可以使用额外的线程实现这一点。 正如你所说的最好的整体(系统)性能我猜最好使用异步I / O而不是多线程(因此减少线程切换)。 我们来看看网络服务器程序的可能实现,它将处理并行连接的1000个客户端: 每个连接一个线程(可以阻塞I / O,但也可以是非阻塞I / O)。 每个线程需要内存资源(也是内核内存!),这是一个缺点。 并且每个额外的线程意味着更多的调度器的工作。 所有连接的一个线程。 这需要系统的负载,因为我们有更少的线...

图数据库上的非阻塞I / O.(Non-blocking I/O on graph database)

我不知道任何语言的任何非阻塞客户端Rexster(不确定Go的那个)。 我假设您可以通过RexPro构建这样的客户端。 请注意,当“Gremlin Server”取代Rexster时,TinkerPop3将拥有这样的客户端。 您可以在这里阅读更多关于它以及它如何影响控制台的内容。 I'm not aware of any non-blocking clients to Rexster in any language (wasn't sure about the one for Go). I wou...

非阻塞I / O问题(Non-blocking I/O issue)

问题是:这个解决方案在CPU使用方面有多好? 使用select / poll / epoll会更有效吗? 这非常低效。 这可能是处理多个连接的最糟糕方式。 考虑每个recv是一个系统调用:它需要一个上下文切换。 上下文切换并不昂贵,但在高频环路中计算上下文切换可能会占用CPU。 此外,如果你在一个电话和另一个电话之间睡觉,为了“软化循环”,你最终会在数据接收和处理之间付出延迟; 你拥有的联系越多,感觉就越高。 select基本上告诉内核:“我希望你监视这些fds集合,并在发生某些事情时立即发出信号...

相关文章

更多

Hadoop的I/O

1. 数据完整性:任何语言对IO的操作都要保持其数据的完整性。Hadoop当然希望数据在存储和处理中不 ...

Hadoop I/O系统介绍

看过很多Hadoop介绍或者是学习的帖子和文章,发现介绍Hadoop I/O系统的很少。很多文章都会介 ...

Hadoop1.0.4 HDFS I/O性能测试

分布式RDF查询引擎的项目需要在节点之间传输中间结果,考虑HDFS可以作为一个备选的传输媒介,于是对H ...

Java中如何用I/O流读取一个Word文档的内容?

BufferedReader br = new BufferedReader(new FileRead ...

O2O

啥是O2O?一句两句话解释不清楚,行业也没有统一的定义,O2O的英文全拼是Online To Offl ...

WiFi入口流量O2O微应用平台

WiFi入口流量O2O微应用平台 随着智能手机一年比一年销量大好,传统的互联网的流量争夺战场已经转向 ...

I18n的一个问题

升级了,2.2.2, 用了I18n. 问题来了。 以前model validation 出错的默认消 ...

最新问答

更多

公共表格表达的PIVOT(PIVOT on Common Table Expression)

WITH details AS ( SELECT FldId ,Rev ,Words ,row_number() OVER ( PARTITION BY FldId ORDER BY Rev DESC ) AS rn FROM WorkItemLongTexts WHERE ID = 2855

spring-ws-security依赖冲突(spring-ws-security dependency conflict)

问题是你已经包含了一个与更新版本相同的依赖关系我认为这样做可以解决它。 将它添加到spring-ws-security依赖声明中。 org.apache.santuario xmlsec Problem is you are already in

redis set集合如何去重

$key = 'URL_HASH'; if(!$redis->hGet($key, md5($url))){ // do something ... // 抓取一个 $url 后 $redis->hSet($key, md5($url), true); } 这里需要注意的是,如果是多线程的,要考虑其他进程,可以吧 bool 值改为枚举值。

在IE中传递ac#文本框作为javascript参数(Chrome作品)(Passing a c# Textbox as a javascript parameter in IE (Chrome works))

用引号括起<%=TextTitu.ClientID%> ,如下所示: ChangeText("<%=TextTitu.ClientID%>", "", ""); 您当前的代码评估为: ChangeText(ctl00_c_area_conteudo_TextTitu, "", ""); 但ctl00_c_area_conteudo_TextTitu没有在任何地方定义为变量,这就是错误引发的原因。 将其包含在引号中后,代码将评估为: ChangeText("ctl0

调用sw程序时地址超出范围(address out of range when calling sw procedure)

sw是一个指令 ,而不是一个程序。 无论如何, sw的目的是将寄存器的内容存储在内存中。 这听起来像你只是想将一个寄存器的内容复制到另一个寄存器,所以你应该使用的指令是move : move $t3,$v0 # $t3 = $v0 同样的事情可以通过其他几种方式实现,例如: or $t3,$v0,$zero 但如果你刚开始使用MIPS汇编,我建议你只使用move 。 sw is an instruction, not a procedure. Anyway, the purpose o

中出是什么意思啊?

日语“中出し”,即“膣内*中出*(体内中出)”的俗称,目前已成为青少年间新兴网络用语。关于“体内中出”,请参考“安全性行为”。 日语,念shiroto ,指非专业人士,业余爱好者,业余艺术家,跟英文Amateur的意思是一样,有时也指良家妇女。

在Android中创建ViewPager或等效的WITH功能(Create a ViewPager or equivalent WITH functionality in Android)

将Activity作为ViewPager的一部分是不可能的,但是没有理由不能将您描述的功能添加到ViewPager中的每个页面。 要为每个视图中的组件分配交互或事件,只需在每个case语句中的instantiateItem()中添加正确的侦听器: case 0: v = inflater.inflate(R.layout.dashboard_social, null); Button myButton = (Button) v.findViewById(R.id.name

如何在Windows启动时自动启动应用程序?(How to make an application automatically start at Windows start?)

如果它自动启动你可以使它成为一个Windows服务,或者你可以简单地将它放在Windows启动文件夹中,它将自动启动它。 对于系统托盘,您应该查看NotifyIcon控件。 As far as having it start automatically you can make it a windows service or you can simply place it in the windows startup folder and it will automatically launch

如何在javafx和scenebuilder中单击按钮时创建新标签?(How to create a new label when a button is clicked in javafx and scenebuilder?)

让我们制作一个窗格并在scenebuilder中设置fx:id(paneLoadLabel) 在控制器中写下这个 @FXML private Pane panelLoadLabel; @FXML public void enterTextMouse(MouseEvent e){ Label lbl1 = new Label(txtCmd.getText()); paneLoadLabel.getChildren().add(lbl1); } Let's make one pa