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

Multithreading 非阻塞I/O真的比多线程阻塞I/O快吗?怎么用?,multithreading,io,blocking,nonblocking,Multithreading,Io,Blocking,Nonblocking,我在网上搜索了一些关于阻塞I/O和非阻塞I/O的技术细节,我发现有几个人说非阻塞I/O比阻塞I/O更快。例如,在 如果我使用阻塞I/O,那么当前被阻塞的线程当然不能做任何其他事情。。。因为它被封锁了。但是,一旦一个线程开始被阻塞,操作系统就可以切换到另一个线程,直到对被阻塞的线程做了一些事情后再切换回来。因此,只要系统上还有另一个线程需要CPU且未被阻塞,那么与基于事件的非阻塞方法相比,不应该有更多的CPU空闲时间,是吗 除了减少CPU空闲时间之外,我还看到了一个增加计算机在给定时间范围内可以执

我在网上搜索了一些关于阻塞I/O和非阻塞I/O的技术细节,我发现有几个人说非阻塞I/O比阻塞I/O更快。例如,在

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

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

  • 要加载文件内容,应用程序将此任务委托给基于事件的i/o框架,并传递回调函数和文件名
  • 事件框架委托给操作系统,操作系统对硬盘的DMA控制器进行编程,以将文件直接写入内存
  • 事件框架允许运行更多的代码
  • 完成磁盘到内存的复制后,DMA控制器会导致中断
  • 操作系统的中断处理程序通知基于事件的i/o框架文件已完全加载到内存中。它是怎么做到的?使用信号
  • 当前在事件i/o框架内运行的代码完成
  • 基于事件的i/o框架检查其队列,查看来自步骤5的操作系统消息,并执行在步骤1中得到的回调

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

    据我所知,改进之处在于异步I/O使用了so(我说的是MS系统,只是为了澄清一下)。通过使用异步调用,框架可以自动利用这种体系结构,这应该比标准线程机制更有效。作为个人经验,我可以说,如果您喜欢异步调用而不是阻塞线程,您会感觉应用程序更具反应性。

    非阻塞I/O的一种可能实现正是您所说的,使用一个后台线程池,这些线程执行阻塞I/O操作,并通过某种回调机制通知I/O发起人的线程。事实上,glibc中的模块就是这样工作的。是关于实施的一些模糊细节


    虽然这是一个很好的可移植解决方案(只要有线程),但操作系统通常能够更有效地为非阻塞I/O提供服务。列出线程池之外的可能实现。

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

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

  • 每个连接一个线程(可以是阻塞I/O,也可以是非阻塞I/O)。
    每个线程都需要内存资源(还有内核内存!),这是一个缺点。每增加一个线程意味着调度器要做更多的工作
  • 一个线程用于所有连接。
    这将从系统中获取负载,因为我们的线程更少。但这也会妨碍您充分利用机器的性能,因为您可能最终会将一个处理器的性能提高到100%,而让所有其他处理器闲置
  • 几个线程,每个线程处理一些连接。
    这会从系统中获取负载,因为线程较少。它可以使用所有可用的处理器。在Windows上,此方法受支持
  • 当然,拥有更多线程本身并不是问题。正如您可能已经认识到的,我选择了相当多的连接/线程。如果我们只讨论十几个线程(这也是Raymond Chen在MSDN博客上的建议),我怀疑您是否会看到这三种可能的实现之间的任何差异

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

    您描述的步骤1到步骤7给出了它的工作原理。在Windows上,操作系统将通知您使用事件或回调完成异步I/O(
    WriteFile
    ,具有
    OVERLAPPED
    结构)。仅当代码调用
    WaitForMultipleObjectsEx
    并将
    bAlertable
    设置为
    true
    时,才会调用回调函数

    更多关于网络的阅读:

    • 在MSDN上,还将很快处理创建线程的成本
    • 第节说:“虽然线程相对容易创建和使用,但操作系统分配了大量的时间和其他资源来管理它们。”
    • 表示“但是,如果您为每个处理器创建一个线程,并构建应用程序维护上下文信息的请求队列,那么您的应用程序将具有更好的性能。”