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

时间:2009-04-15 22:52:16

标签: winapi io crystal-reports io-completion-ports

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

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

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

6 个答案:

答案 0 :(得分:34)

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

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

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

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

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

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

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

撇开;恕我直言,你真的应该阅读杰弗里里希特和克里斯托夫纳萨尔的“Windows Via C/C++ (PRO-Developer)”,因为它将提供有关重叠I / O和大多数其他高级Windows平台技术和API的所有信息。

答案 1 :(得分:7)

WaitForMultipleObjects限制为64个句柄;在高度并发的应用程序中,这可能成为一种限制。

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

然而,完成端口和基于事件的编程模型是一个更难理解的概念。

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

答案 2 :(得分:5)

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

答案 3 :(得分:2)

WaitForMultipleObjects()和I / O完成端口之间的区别在于IOCP可以扩展到数千个对象,而WFMO()不会也不应该用于超过64个对象(即使你可以)。

你无法真正比​​较它们的性能,因为在<域中64个对象,它们基本相同。

但是,WFMO()会在其对象上进行循环,因此索引号较低的繁忙对象可能会使具有高索引号的对象饿死。 (例如,如果物体0不断地熄灭,它将使物体1,2,3等挨饿)。这显然是不可取的。

我写了一个IOCP库(用于套接字)来解决C10K问题并将其置于公共领域。我能够在512mb W2K机器上同时传输4,000个套接字传输数据。 (你可以获得更多的套接字,如果它们处于空闲状态 - 繁忙的套接字消耗更多的非分页池,这是你可以拥有多少个套接字的最终限制。)

http://www.45mercystreet.com/computing/libiocp/index.html

API应该能够满足您的需求。

答案 4 :(得分:0)

不确定。但我使用WaitForMultipleObjects和/或WaitFoSingleObjects。这很方便。

答案 5 :(得分:0)

任何一种常规工作,我都不认为一个比另一个更快。

这两种方法的存在是为了满足不同的编程模型。 WaitForMultipleObjects用于促进异步完成模式(如UNIX select()函数),而完成端口则更倾向于事件驱动模型。

我个人认为WaitForMultipleObjects()方法可以使代码更清晰,线程更安全。