3

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

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

我知道 IOCP 的东西与CreateThreadpoolIoetc. 结合使用 OS 线程池。但是,“正常”的重叠 I/O 也必须使用单独的线程吗?那么有什么区别/缺点?我的回调是否由 I/O 线程调用并阻止其他内容?

在此先感谢,克里斯托夫

4

2 回答 2

2

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

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

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

于 2013-08-02T19:03:56.843 回答
0

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

如果您考虑一下,您就会明白原因:应该尽快为事件提供完整的服务(或在初始处理后将其放入某个队列中)。假设 5 个事件排队到 4 核计算机上的 IOCP。如果有 8 个线程与 IOCP 相关联,则调度程序可能会中断一个事件以使用另一个低效的线程开始为另一个事件提供服务。如果被中断的线程位于临界区中,也可能很危险。使用四个线程,您可以同时处理四个事件,一旦一个事件完成,您就可以从 IOCP 队列中的最后一个剩余事件开始。

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

编辑__ _ __ _ __ _ __ _ __ _ _

套接字(文件句柄也可以正常工作)与 IOCP 相关联。完成例程在 IOCP 上等待。一旦请求的对套接字的读取或写入完成操作系统 - 通过 IOCP - 释放等待 IOCP 的完成例程并返回您在调用读取或写入时提供的附加信息(我通常将指针传递给一个控制块)。因此,完成例程立即“知道”在哪里找到与完成相关的信息。

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

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

因此,基于 IOCP 的应用程序通常消耗很少(或不消耗)CPU,直到完成发生,此时完成例程完全倾斜,直到完成处理,发送新的 I/O 请求并再次等待完成端口. 除了 IOCP 超时(可用于指示内务处理等)之外,所有与 I/O 相关的东西都发生在操作系统中。

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

于 2013-08-15T13:45:21.953 回答