我应该使用IOCP还是重叠的WSASend / Receive?

时间:2013-08-02 13:45:59

标签: sockets asynchronous winsock iocp

我正在调查Windows上异步套接字I / O的选项。显然有多个选项:我可以使用WSASend ...重叠结构提供完成回调或事件,或者我可以使用IOCP和(新)线程池。从我通常阅读,后一个选项是推荐的选项。

但是,我不清楚,如果完成例程足以满足我的目标,为什么我应该使用IOCP:告诉套接字发送这个数据块并通知我它是否完成。

我理解IOCP内容与CreateThreadpoolIo等结合使用操作系统线程池。但是,“正常”重叠I / O还必须使用单独的线程?那么差异/劣势是什么?我的回调是由I / O线程调用并阻止其他东西吗?

提前致谢, 克里斯托弗

2 个答案:

答案 0 :(得分:2)

您可以使用但是,对于服务器,具有“完成队列”的IOCP通常会有更好的性能,因为它可以使用多个客户端<>服务器线程,使用CreateThreadpoolIo或某些用户空间线程池。显然,在这种情况下,通常使用专用处理程序线程。

重叠完成例程I / O对客户端更有用,恕我直言。完成例程由异步过程调用触发,该异步过程调用排队到发起I / O请求的线程(WSASend,WSARecv)。这意味着该线程必须处于处理APC的位置,这通常意味着围绕某些'blahEx()'调用的while(true)循环。这很有用,因为在阻塞队列或其他线程间信号上等待很容易,它允许为线程提供要发送的数据,并且完成例程总是由该线程处理。这种I / O机制使'hEvent'OVL参数可以自由使用 - 非常适合将通信缓冲区对象指针传递给完成例程。

应避免使用实际同步事件/信号量/重叠hEvent参数的重叠I / O.

答案 1 :(得分:0)

Windows IOCP文档建议每个完成端口的每个可用核心不超过一个线程。超线程使核心数量翻倍。由于使用IOCP导致所有实际用途的事件驱动应用程序,使用线程池会给调度程序添加不必要的处理。

如果你仔细想想,你就会明白为什么:一个事件应该尽快完整地服务(或者在初始处理之后放在一个队列中)。假设五个事件排队到4核计算机上的IOCP。如果有八个与IOCP相关联的线程,则存在调度程序通过使用效率低下的另一个线程来中断一个事件以开始为另一个事件服务的风险。如果断开的螺纹位于临界区域内,也可能是危险的。使用四个线程,您可以同时处理四个事件,只要一个事件完成,您就可以从IOCP队列中的最后一个剩余事件开始。

当然,您可能拥有用于非IOCP相关处理的线程池。

修改 __ _ __ _ __ _ __ < EM> _ __ _ _

套接字(文件句柄也能正常工作)与IOCP相关联。完成例程等待IOCP。只要请求读取或写入套接字完成操作系统 - 通过IOCP - 就会释放等待IOCP的完成例程,并返回您在调用读取或写入时提供的其他信息(我通常会将指针传递给控制块)。因此,完成例程立即“知道”找到与完成相关的信息的位置。

如果您传递了涉及控制块(类似)的信息,则该控制块(可能)需要跟踪已完成的操作,因此它知道下一步该做什么。 IOCP本身既不知道也不关心。

如果您正在编写连接到Internet的服务器,则服务器将发出读取以等待客户端输入。该输入可能在一毫秒或一周后到达,当它发出时,IOCP将释放分析输入的完成例程。通常,它使用包含输入中请求的数据的写入进行响应,然后等待IOCP。当写入完成后,IOCP再次释放完成例程,该例程看到写入已完成,(通常)发出新读取并开始新的循环。

因此,基于IOCP的应用程序通常消耗非常少(或没有)的CPU,直到完成发生的那一刻,完成例程完全倾斜,直到它完成处理,发送新的I / O请求并再次等待完成港口。除了IOCP超时(可用于发信号通知等),所有与I / O相关的内容都会出现在操作系统中。

为了进一步复杂化(或简化)事情,不需要使用WSA例程来处理套接字,Win32函数ReadFile和WriteFile工作得很好。