gpt4 book ai didi

winapi - I/O 完成端口 vs. RegisterWaitForSingleObject?

转载 作者:行者123 更新时间:2023-12-04 14:39:46 26 4
gpt4 key购买 nike

使用 I/O 完成端口与仅使用 RegisterWaitForSingleObject 来让线程池线程等待 I/O 完成有什么区别?

其中之一是否更快,如果是这样,为什么?

最佳答案

IOCP 通常是您会发现的执行速度最快的 IO 周转机制,原因之一是:阻塞检测。

一个简单的例子是一个负责从磁盘提供文件的服务器。 IOCP 通常由三个主要部分组成:

  • 用于服务 IOCP 请求的 N 个线程池。
  • M 个线程的限制(M 总是 < N),它告诉 IOCP 允许有多少并发、非阻塞线程。
  • 所有线程运行的完成状态循环。

  • N和M在这方面的区别很重要。一般的理念是将 M 配置为机器上的内核数,而 N 配置为更大。多大取决于您的工作线程在阻塞状态中花费的时间。如果您正在读取磁盘文件,您的线程将受限于磁盘 IO channel 的速度。当您调用 ReadFile() 时,您刚刚引入了一个阻塞调用。如果 M == N,那么一旦您命中所有读取磁盘文件的线程,您就会完全停止,所有线程都在磁盘 IO channel 上。

    但是,如果某个奇特的调度程序有办法“知道”该线程正在 (a) 参与 IOCP 线程池,并且 (b) 只是因为它发出了一个耗时的 API 调用而停止了呢?如果发生这种情况时,那个花哨的调度程序可以暂时将该线程“移动”到一个特殊的“运行但停止”组中,然后“释放”一个额外的线程,该线程在线程停止时自愿工作,该怎么办?

    这正是 IOCP 带来的。当 N 大于 M 时,IOCP 会将刚刚发出暂停的线程置于特殊的 running-but-stalled 状态,然后临时从您的 N 池中“借用”一个额外的线程。它将继续这样做,直到N 池已耗尽,或者停止的线程开始从它们的阻塞请求中返回。

    因此,在这种情况下,一个 IOCP 配置为在 8 核机器上同时运行 8 个线程,实际上实际池中可能有几百个线程。只有 8 个将永远被“允许”在非阻塞状态下并发运行,尽管当阻塞的线程从它们的块返回并且您已经借用了服务于其他请求的线程时,您可能会暂时弹出它。

    最后,虽然对您的原因不那么重要,但它仍然很重要:如果 IOCP 线程在完成当前工作并发出下一个 GetQueueCompletionStatus() 调用时队列上有待处理的工作,则它不会阻塞,也不会上下文切换。如果有工作在等待,它将捡起它并继续执行而无需强制抢占。当然操作系统调度程序无论如何都可以抢占,但只是作为通用调度程序的一部分;不是因为对 GetQueueCompletionStatus() 的特定调用。唯一的异常(exception)是,如果已经有超过 M 个线程正在运行且未被阻塞。在这种情况下, GetQueueCompletionStatus() 将阻塞调用线程,直到当足够多的线程再次阻塞时再次需要它来进行 slack-work。

    您给出的描述表明您将受到大量磁盘 io 的限制。对于绝对对性能至关重要的 io-server 架构,几乎不可能超越 IOCP 的优势,尤其是操作系统级别的块检测,它允许调度程序知道它可以暂时从主池中释放额外的线程以保留事物在其他线程停止时泵送。

    您根本无法使用 Windows 线程池复制 IOCP 的特定功能。如果您的所有线程都是 IO 很少或没有 IO 的数字处理器,我会说线程池更合适,但是您对磁盘 IO 的特殊性告诉我您应该改用 IOCP。

    关于winapi - I/O 完成端口 vs. RegisterWaitForSingleObject?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16243248/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com