Win32重叠I/O - 完成例程还是WaitForMultipleObjects?

19 io winapi crystal-reports io-completion-ports

我想知道哪种方法更快,为什么?

在编写Win32服务器的过程中,我已经阅读了很多有关完成端口和重叠I/O的内容,但是我没有读过任何内容来暗示哪一组API在服务器中产生最佳结果.

我应该使用完成例程,还是应该使用WaitForMultipleObjects API?为什么?

Len*_*ate 34

您建议两种方法进行重叠I/O并忽略第三种方法(或者我误解了您的问题).

例如,当您发出重叠操作(例如WSARecv())时,您可以指定包含事件的OVERLAPPED结构,并且可以等待该事件发出信号以指示重叠的I/O已完成.我假设这是您的WaitForMultipleObjects()方法,并且如前所述,由于您可以将传递给WaitForMultipleObjects()的句柄数量限制,因此这不能很好地扩展.

或者,您可以传递完成例程,该例程在完成时调用.这称为"可警告I/O",并要求发出WSARecv()调用的线程处于"可警告"状态,以便调用完成例程.线程可以通过多种方式将自己置于可警告状态(调用SleepEx()或等待函数的各种EX版本等).我在我面前打开的里希特书中写道:"我已经开始使用可警告的I/O了,我会第一个告诉你,可警告的I/O很糟糕,应该避免".恕我直言.

还有第三种方法,在发出调用之前,您应该将要执行重叠I/O的句柄与完成端口相关联.然后,您可以通过调用GetQueuedCompletionStatus()并循环来创建一个服务此完成端口的线程池.使用OVERLAPPED结构发出WSARecv(),其中没有事件,当I/O完成完成时,会在其中一个I/O池线程上弹出GetQueuedCompletionStatus(),并且可以在那里处理.

如前所述,Vista/Server 2008已经清理了IOCP如何工作一点并解决了问题,因此您必须确保发出重叠请求的线程继续运行直到请求完成.可以在此处找到对该引用的链接.但无论如何这个问题很容易解决; 您只需使用与完成时使用的相同IOCP将WSARecv封送到您的一个I/O池线程中...

无论如何,使用IOCP的IMHO是进行重叠I/O的最佳方式.是的,了解调用的重叠/异步性质可能会在开始时花费一些时间,但它非常值得,因为系统可以很好地扩展并提供一种处理重叠操作的简单"即发即忘"方法.

如果您需要一些示例代码来帮助您,那么我有几篇关于编写IO完成端口系统和一堆免费代码的文章,这些代码为高性能服务器提供了真实的框架.看到这里.

作为旁白; 恕我直言,你真的应该阅读Jeffrey Richter和Christophe Nasarre撰写的" Windows Via C/C++(PRO-Developer) ",因为它可以让您了解重叠I/O和大多数其他高级Windows平台技术和API.


Ric*_*ard 7

WaitForMultipleObjects仅限64把手; 在高度并发的应用程序中,这可能成为一种限制.

完成端口更适合具有线程池的模型,所有线程池都能够处理任何事件,并且您可以将自己的(非基于IO的)事件排队到端口中,而等待则需要编写自己的代码机制.

然而,完成端口和基于事件的编程模型是一个更难以实现的概念.

我不希望有任何明显的性能差异,但最终您只能自己测量以反映您的使用情况.请注意,Vista/Server2008使用完成端口进行了更改,现在不需要原始线程来完成IO操作,这可能会产生更大的差异(请参阅Mark Russinovich 撰写的这篇文章).


Aar*_*otz 5

" 网络编程for Microsoft Windows"第2版中的表6-3 比较了通过完成端口与其他技术重叠I/O的可扩展性.完成端口在吞吐量方面将所有其他I/O模型从水中吹走,同时使用更少的线程.