Winapi I/O完成端口与RegisterWaitForSingleObject?

Winapi I/O完成端口与RegisterWaitForSingleObject?,winapi,visual-c++,file-io,asynchronous,io-completion-ports,Winapi,Visual C++,File Io,Asynchronous,Io Completion Ports,使用I/O完成端口与仅使用线程池线程等待I/O完成有什么区别 其中一个是否更快?如果是,原因是什么?IOCP通常是执行IO掉头机制最快的机制,原因有一个:阻塞检测 这方面的一个简单示例是负责从磁盘提供文件的服务器。IOCP通常由三个主要部分组成: 为IOCP请求提供服务的N个线程池 限制M个线程(M总是

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


其中一个是否更快?如果是,原因是什么?

IOCP通常是执行IO掉头机制最快的机制,原因有一个:阻塞检测

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

  • 为IOCP请求提供服务的N个线程池
  • 限制M个线程(M总是
  • 所有线程运行的完成状态循环
  • 在这方面,N和M之间的差异非常重要。一般原理是将M配置为机器上的磁芯数,将N配置为更大。其大小取决于工作线程在阻塞状态下花费的时间。如果正在读取磁盘文件,则线程将绑定到磁盘IO通道的速度。当您调用
    ReadFile()
    时,您刚刚引入了一个阻塞调用。如果M==N,那么只要点击读取磁盘文件的所有线程,就会完全停止,所有线程都在磁盘IO通道上

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

    这正是IOCP带来的。当N大于M时,IOCP将使刚刚发出暂停的线程进入特殊的运行但暂停状态,然后从N池中临时“借用”一个额外的线程。它将继续这样做,直到N池耗尽,或者暂停的线程开始从阻塞请求返回

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

    最后,尽管对您的原因来说并不重要,但它仍然很重要:当IOCP线程完成当前工作并发出下一个
    GetQueueCompletionStatus()
    调用时,如果队列上存在挂起的工作,则IOCP线程不会阻塞,也不会切换上下文。如果有工作等待,它将拿起它并继续执行,而不强制抢占。当然,OS调度器可能会抢占,但只能作为常规调度器的一部分;不是因为对
    GetQueueCompletionStatus()
    的特定调用。唯一的例外是,如果已经有超过M个线程在运行且未阻塞。在这种情况下,
    GetQueueCompletionStatus()
    将阻塞调用线程,直到当足够多的线程再次被阻塞时,需要它来执行空闲工作

    您给出的描述表明您将受到严重的磁盘io限制。对于绝对性能关键的io服务器体系结构,几乎不可能比IOCP更好,尤其是操作系统级的块检测,它允许调度程序知道它可以临时从主池中释放额外的线程,以便在其他线程停止时保持运行


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

    “更快”是一个与手头任务相关的术语。你计划做(或实际做)什么?这两种技术明显不同,因此了解您试图实现的目标将非常重要,因为它更适合您的问题。@WhozCraig:我正在进行大量的磁盘读取和处理数据;瓶颈是I/O,因此目标是实现最大吞吐量(来自不同磁盘的数据将并行读取,而来自同一磁盘的数据将串行读取)。我觉得这两个都适用于我的设计,我只是不知道该使用哪一个。此外,IOCP使用了不公平的调度(处于休眠状态的线程倾向于保持休眠状态,正在运行的线程倾向于保留在内存中),这意味着您可以使N变得非常大,而不必担心破坏调度程序和内存管理器。我刚刚意识到
    QueueUserWorkItem
    WT_EXECUTEDEFAULT
    文档中说“回调函数排队到使用I/O完成端口的线程”,然而,
    RegisterWaitForSingleObject
    的同一标志文档不包含该语句。您知道
    RegisterWaitForSingleObject
    是否也对
    WT_EXECUTEDEFAULT
    使用IOCP吗?如果是这样,那么使用
    RegisterWaitForSingleObject
    对我来说是否同样有效?(根据WINE的说法,他们都使用了
    RtlQueueWorkItem
    ,所以他们很可能是一样的…@Mehrdad我不这么认为,但确实如此(这个名字有点像是一个死赠品)。在设置绑定之前,请确保检查IO请求的结果,这是一个重要的警告。它一定返回了错误“IO”挂起,否则您将发出一个永远不会出现的回调请求。@WhozCraig:Ooh,谢谢提醒。我刚刚对
    RtlRegisterWait
    进行了快速反汇编,发现它使用了
    NtQueueApcThread