首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >非阻塞I/O真的比多线程阻塞I/O快吗?多么?

非阻塞I/O真的比多线程阻塞I/O快吗?多么?
EN

Stack Overflow用户
提问于 2011-12-18 00:45:52
回答 9查看 43.4K关注 0票数 131

我在网上搜索了一些关于阻塞I/O和非阻塞I/O的技术细节,我发现一些人声称非阻塞I/O将比阻塞I/O更快,例如在this document中。

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

除了减少CPU空闲时间外,我还看到了增加计算机在给定时间范围内可以执行的任务数量的另一个选择:减少切换线程带来的开销。但如何才能做到这一点呢?开销是否足够大,以显示可测量的影响?这里有一个我可以想象它是如何工作的想法:

为了加载文件的内容,应用程序将此任务委托给基于事件的i/o框架,将回调函数和文件名一起传递给基于事件的i/o框架。

  • 事件框架委托给操作系统,操作系统对硬盘的

  • 控制器进行编程,以将文件直接写入内存

  • 事件框架允许进一步的代码运行。

  • 在完成磁盘到内存的复制后,DMA控制器使DMA操作系统的中断处理程序通知基于事件的I/O框架文件已完全加载到内存中。它如何做到这一点呢?使用signal??

  • 当前在事件i/o框架内运行的代码基于事件的i/o框架检查其队列,查看来自步骤5的操作系统消息,并执行在步骤1中获得的回调。

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

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2011-12-18 01:11:10

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

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

  1. 每个连接一个线程(可以是阻塞I/O,也可以是非阻塞I/O)。

每个线程都需要内存资源(也需要内核内存!),这是一个缺点。每增加一个线程就意味着调度器需要做更多的工作。

  • 为所有连接分配一个线程。

这需要从系统中加载,因为我们有更少的线程。但它也会阻止你充分利用机器的性能,因为你可能最终会将一个处理器的性能提高到100%,而让所有其他处理器闲置。

  • 几个线程,每个线程处理一些连接。

这需要从系统中加载,因为有更少的线程。它可以使用所有可用的处理器。在Windows上,Thread Pool API.支持这种方法。

当然,拥有更多的线程本身并不是问题。正如您可能已经注意到的,我选择了相当多的连接/线程。如果我们只讨论十几个线程,我怀疑你会发现这三种可能的实现之间有什么不同(这也是Raymond Chen在MSDN博客文章Does Windows have a limit of 2000 threads per process?上建议的)。

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

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

更多关于网络的阅读:

MSDN上的

),则应用程序的性能会更好。

票数 50
EN

Stack Overflow用户

发布于 2013-05-14 02:38:05

I/O包括多种操作,如从硬盘读取和写入数据、访问网络资源、调用web服务或从数据库检索数据。根据平台和操作类型的不同,异步I/O通常会利用任何硬件或低级系统支持来执行操作。这意味着它将在对CPU影响尽可能小的情况下执行。

在应用程序级别,异步I/O避免了线程必须等待I/O操作完成。一旦启动异步I/O操作,它就会释放启动该操作的线程,并注册一个回调。操作完成后,回调将排队等待在第一个可用线程上执行。

如果I/O操作是同步执行的,它将使其正在运行的线程在该操作完成之前什么也不做。运行时不知道I/O操作何时完成,因此它会定期为等待线程提供一些CPU时间,这些CPU时间本来可以被其他有实际CPU限制操作要执行的线程使用。

因此,正如@user1629468所提到的,异步I/O并没有提供更好的性能,而是提供了更好的可伸缩性。当运行在线程数量有限的上下文中时,这一点很明显,就像web应用程序的情况一样。Web应用程序通常使用线程池,它们从线程池中为每个请求分配线程。如果长时间运行的I/O操作上的请求被阻塞,则存在耗尽web池并使web应用程序冻结或响应缓慢的风险。

我注意到的一件事是,异步I/O在处理非常快的I/O操作时不是最佳选择。在这种情况下,在等待I/O操作完成时不让线程保持忙碌的好处并不是很重要,并且操作是在一个线程上启动而在另一个线程上完成的事实增加了整个执行的开销。

您可以阅读我最近关于异步I/O与多线程here主题的更详细的研究。

票数 33
EN

Stack Overflow用户

发布于 2015-06-01 08:22:48

要假定由于任何形式的多计算而带来的速度提高,您必须假定多个基于CPU的任务在多个计算资源(通常是处理器核心)上同时执行,或者不是所有的任务都依赖于对相同资源的并发使用--也就是说,一些任务可能依赖于一个系统子组件(比如磁盘存储),而一些任务依赖于另一个子组件(接收来自外围设备的通信),还有一些任务可能需要使用处理器核心。

第一种情况通常被称为“并行”编程。第二种情况通常被称为“并发”或“异步”编程,尽管“并发”有时也被用来指仅允许操作系统交错执行多个任务的情况,而不管这样的执行是否必须串行地发生,或者是否可以使用多个资源来实现并行执行。在后一种情况下,“并发”通常是指在程序中编写执行的方式,而不是从任务执行的实际同时性的角度来看。

用默认的假设来谈论这一切是很容易的。例如,有些人很快就会声称“异步I/O将比多线程I/O更快”。这一说法值得怀疑,原因有几个。首先,可能的情况是,某些给定的异步I/O框架正是通过多线程实现的,在这种情况下,它们是同一个概念中的一个,说一个概念“比”另一个概念“快”是没有意义的。

其次,即使在异步框架的单线程实现(例如单线程事件循环)的情况下,您仍然必须假设该循环正在做什么。例如,对于单线程事件循环,您可以做的一件愚蠢的事情就是请求它异步完成两个完全受CPU限制的不同任务。如果您在只有一个理想化的单处理器内核(忽略现代硬件优化)的机器上执行此任务,那么“异步”执行此任务与使用两个独立管理的线程或仅使用一个单独的进程执行该任务没有什么不同--差异可能归结为线程上下文切换或操作系统调度优化,但如果两个任务都由CPU执行,则在任何一种情况下都是相似的。

想象一下你可能会遇到的许多不寻常或愚蠢的角落案例是很有用的。

“异步”不必是并发的,例如,如上所述:您在一台只有一个处理器核心的机器上“异步”执行两个CPU绑定的任务。

多线程执行不必是并发的:您可以在具有单个处理器核心的机器上生成两个线程,或者要求两个线程获取任何其他类型的稀缺资源(假设一个网络数据库一次只能建立一个连接)。无论操作系统调度器如何认为合适,线程的执行可能是交错的,但是它们的总运行时间不能在单个内核上减少(线程上下文切换会增加)(或者更一般地说,如果您产生的线程比运行它们的内核多,或者请求资源的线程比资源所能支持的线程多)。同样的事情也适用于多进程。

因此,异步I/O和多线程都不必在运行时间方面提供任何性能提升。他们甚至可以放慢速度。

但是,如果您定义了一个特定的用例,比如一个特定的程序,它既进行网络调用以从远程数据库等网络连接的资源中检索数据,又执行一些本地CPU限制的计算,那么您可以在给定硬件的特定假设的情况下,开始推断这两种方法之间的性能差异。

要问的问题是:我需要执行多少计算步骤,以及有多少独立的资源系统来执行它们?是否有计算步骤的子集需要使用独立的系统子组件,并且可以同时受益于此?我有多少个处理器核心?使用多个处理器或线程在不同核心上完成任务的开销是多少?

如果您的任务在很大程度上依赖于独立的子系统,那么异步解决方案可能是好的。如果需要处理它的线程数量很大,使得上下文切换对于操作系统来说变得非常重要,那么单线程异步解决方案可能会更好。

当任务由相同的资源绑定时(例如,多个需要并发访问相同的网络或本地资源),那么多线程可能会引入不令人满意的开销,虽然单线程异步可能引入较少的开销,但在这种资源有限的情况下,它也不能产生加速。在这种情况下,唯一的选择(如果您想要加速)是使该资源的多个副本可用(例如,如果稀缺资源是CPU,则多个处理器核心;如果稀缺资源是连接受限数据库,则更好的数据库支持更多的并发连接,等等)。

另一种方式是:允许操作系统交错使用两个任务的单个资源,这不会比仅仅让一个任务使用资源而另一个任务等待,然后让第二个任务串行完成更快。此外,交织的调度器成本意味着在任何实际情况下,它实际上都会造成减速。CPU、网络资源、存储器资源、外围设备或任何其他系统资源的交叉使用都无关紧要。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8546273

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档