5

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

  1. 在所有这些句柄上调用 WaitForMultipleObjects
  2. boost::windows::basic_handle 上的 async_read 围绕所有这些句柄

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

4

2 回答 2

10

因为听起来你从 asio 获得的主要用途是它建立在 IO 完成端口(简称 iocp)之上。所以,让我们从比较 iocp 和WaitForMultipleObjects(). 这两种方法与linux 上的selectvs.基本相同。epoll

iocp 解决的主要缺点WaitForMultipleObjects是无法使用许多文件描述符进行扩展。它是 O(n),因为对于您收到的每个事件,您都会再次传入完整的数组,并且内部 WaitForMultipleObjects 必须扫描数组以了解要触发哪些句柄。

然而,由于第二个缺点,这很少成为问题。WaitForMultipleObjects()它可以等待的最大句柄数有限制 ( MAXIMUM_WAIT_OBJECTS)。此限制为 64 个对象(请参阅 winnt.h)。有一些方法可以绕过这个限制,方法是创建 Event 对象并将多个套接字绑定到每个事件,然后等待 64 个事件。

第三个缺点是WaitForMultipleObjects(). 它返回触发事件的句柄的索引。这意味着它只能将单个事件传回给用户。这与 不同select,后者将返回触发事件的所有文件描述符。WaitForMultipleObjects扫描传递给它的句柄并返回第一个引发其事件的句柄。

这意味着,如果您正在等待 10 个非常活跃的套接字,并且大部分时间所有这些套接字上都有一个事件,那么将非常倾向于为传递给的列表中的第一个套接字提供服务WaitForMultipleObjects。这可以通过以下方式规避:每次函数返回并且事件已得到服务时,以 0 的超时时间再次运行它,但这次仅传递数组 1 中触发事件之后的部分。重复直到所有句柄都被访问,然后返回到所有句柄和实际超时的原始调用。

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

使用 iocp(因此也是 asio):

  1. 你不重复你感兴趣的句柄,你告诉windows一次,它就会记住它。这意味着它可以通过许多句柄更好地扩展。
  2. 您可以等待的句柄数量没有限制
  3. 你得到每一个事件,即没有对任何特定句柄的偏见

我不确定您是否假设async_read在自定义句柄上使用。你可能需要测试一下。如果您的句柄指的是套接字,我想它会起作用。

至于线程问题;是的。如果您run()io_service多个线程中,事件将被分派到一个空闲线程,并将随着更多线程进行扩展。这是 iocp 的一个特性,它甚至还有一个线程池 API。

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

于 2011-06-06T04:53:35.073 回答
1

WaitForSingleObject&都是WaitForMultipleObjects广泛使用的函数,该WaitForSingleObject函数用于等待单个 Thread 同步对象。当对象设置为信号或超时间隔结束时,会发出信号。如果时间间隔为 INFINITE,则无限等待。

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);

WaitForMultipleObjects用于等待多个对象发出信号。在 Semaphore 线程同步对象中,当计数器归零时,该对象是无信号的。Auto reset 事件和 Mutex 在释放对象时未发出信号。手动重置事件确实会影响等待功能的状态。

DWORD WaitForMultipleObjects(
  DWORD        nCount,
  const HANDLE *lpHandles,
  BOOL         bWaitAll,
  DWORD        dwMilliseconds
);

如果dwMillisecondszero,则如果对象未发出信号,则函数不会进入等待状态;它总是立即返回。如果dwMillisecondsINFINITE,该函数将仅在对象发出信号时返回。

于 2019-03-08T13:18:03.803 回答