我有一个由许多不同的IO设备控制的HANDLE列表。之间的(性能)差异是什么?
WaitForMultipleObjects O(n)的时间复杂度是n的句柄数量吗?
您可以以某种方式在windows::basic_handle上调用async_read对吗?还是这个假设是错误的?
如果我在多个线程中的同一IO设备上运行调用,那么这些线程之间的处理调用是否会保持平衡?那将是使用asio的主要好处。
最佳答案
因为这听起来像是您将从asio继承的主要用途,所以它是建立在IO完成端口(简称iocp)之上的事实。因此,让我们开始比较iocp和WaitForMultipleObjects()
。这两种方法本质上与linux上的select
和epoll
相同。
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):
我不确定您是否在自定义句柄上使用
async_read
的假设。您可能必须测试一下。如果您的 handle 指向 socket ,我想它会起作用。至于线程问题;是的。如果您在多个线程中对
run()
进行io_service
编码,则事件将分派(dispatch)到空闲线程,并且将随着更多线程而扩展。这是iocp的功能,它甚至具有线程池API。简而言之:我相信asio或iocp会比仅使用
WaitForMultipleObjects
提供更好的性能,但是该性能是否会为您带来利益,主要取决于您拥有多少个句柄以及它们的活跃程度。