WaitForMultipleObjects

WaitForMultipleObjects

我有一个由许多不同的IO设备控制的HANDLE列表。之间的(性能)差异是什么?

  • 在所有这些句柄上对WaitForMultipleObjects的调用
  • 在boost::windows::basic_handle上的
  • async_read围绕着所有这些句柄

  • WaitForMultipleObjects O(n)的时间复杂度是n的句柄数量吗?
    您可以以某种方式在windows::basic_handle上调用async_read对吗?还是这个假设是错误的?
    如果我在多个线程中的同一IO设备上运行调用,那么这些线程之间的处理调用是否会保持平衡?那将是使用asio的主要好处。

    最佳答案

    因为这听起来像是您将从asio继承的主要用途,所以它是建立在IO完成端口(简称iocp)之上的事实。因此,让我们开始比较iocp和WaitForMultipleObjects()。这两种方法本质上与linux上的selectepoll相同。

    iocp解决的WaitForMultipleObjects的主要缺点是无法缩放许多文件描述符。它是O(n),因为对于您收到的每个事件,您都会再次传递完整的数组,并且内部的WaitForMultipleObjects必须扫描该数组以知道要触发哪个句柄。

    但是,由于第二个缺点,这很少有问题。 WaitForMultipleObjects()对可以等待的最大句柄数(MAXIMUM_WAIT_OBJECTS)有限制。此限制是64个对象(请参见winnt.h)。通过创建Event对象并为每个事件绑定(bind)多个套接字,然后等待64个事件,可以通过多种方法来解决此限制。

    第三个缺点是WaitForMultipleObjects()实际上存在一个细微的“错误”。它返回触发事件的句柄的索引。这意味着它只能将单个事件传达回用户。这不同于select,后者将返回触发事件的所有文件描述符。 WaitForMultipleObjects扫描传递给它的句柄,并返回引发事件的第一个句柄。

    这意味着,如果您正在等待10个非常活跃的套接字,而大多数情况下所有这些套接字都具有一个事件,则对于服务传递给WaitForMultipleObjects的列表中的第一个套接字会有很大的偏见。可以通过以下方法来避免这种情况:每次函数返回并为事件提供服务后,以0超时再次运行它,但这一次仅将数组1的一部分传递给触发事件。重复直到访问完所有句柄,然后返回带有所有句柄和实际超时的原始调用。

    iocp解决了所有这些问题,并且还引入了用于更通用的事件通知的接口(interface),这非常好。

    使用iocp(并因此使用asio):

  • 不再重复您感兴趣的句柄,您只告诉一次窗口,它便会记住它。这意味着它在使用多个 handle 时可扩展性更好。
  • 您没有等待
  • 上的句柄数量的限制
  • 您会收到所有事件,即,对于任何特定句柄
  • 都没有偏见

    我不确定您是否在自定义句柄上使用async_read的假设。您可能必须测试一下。如果您的 handle 指向 socket ,我想它会起作用。

    至于线程问题;是的。如果您在多个线程中对run()进行io_service编码,则事件将分派(dispatch)到空闲线程,并且将随着更多线程而扩展。这是iocp的功能,它甚至具有线程池API。

    简而言之:我相信asio或iocp会比仅使用WaitForMultipleObjects提供更好的性能,但是该性能是否会为您带来利益,主要取决于您拥有多少个句柄以及它们的活跃程度。

    10-04 15:05