用于小型单线程应用程序的 I/O 完成端口?

Posted

技术标签:

【中文标题】用于小型单线程应用程序的 I/O 完成端口?【英文标题】:I/O Completion Port for small-scale, single-threaded applications? 【发布时间】:2014-09-24 15:41:44 【问题描述】:

让我先说一下我从来没有使用过 I/O 完成端口,尽管我已经听说了很多年了。我的背景主要是selectpollepollWSAEventSelect 以及WaitForMulitpleObjects。如果我对以下文本中的 I/O 完成端口有根本的误解,请纠正我。

作为工作项目的一部分,我的任务是为模拟开发一个插件 (DLL),它允许客户端连接到插件并通过 TCP 向/从模拟发送/接收数据。该插件充当服务器。该仿真模拟了不同(不是以太网)接口的通信通道,在这个特定的应用程序中,每个通道都有一个套接字是有意义的。我不知道会有多少个客户端,或者每个客户端会打开多少个通道(套接字)。不过,我知道完全有可能超过 64 个,而且不会是一个特别大的数字,最多可能不到一千。

模拟的一个重要方面是插件仅在其test_cycle 函数被调用时才允许工作。在每个测试周期中,我需要:

    接受来自客户端的任何新连接 从套接字接收数据并将其转发到模拟 从模拟接收数据并将其转发给客户端

由于可能有超过 64 个套接字,我不能(轻松)使用 WSAEventSelectWSAWaitForMultipleEvents 来检查是否可以读取套接字,或者客户端是否已正常终止连接。

所以我想到了另外两种方法可以做到这一点。

    让每个套接字都是非阻塞的。每次调用test_cycle 时,循环遍历所有套接字,尝试接收每个套接字的最大数据量。

    使用 I/O 完成端口并从套接字发出异步接收。在test_cycle 中,重复调用GetQueuedCompletionStatus 并将dwMilliseconds 参数设置为0,直到指示超时(WAIT_TIMEOUT?)。如果发生接收,请将下一次接收调用推迟到测试周期结束,这样客户端向服务器发送垃圾邮件就不会导致我们在test_cycle 中无限循环(希望如此)。

模拟的接口不是线程安全的,将数据转发到模拟的处理工作很少,所以我认为为 I/ 设置工作线程不会有任何好处O 完成端口,它只会做一个锁定并调用模拟 API。但是,不必轮询每个套接字可能会带来更好的性能。

因此,对于这种规模的应用程序,最多少于 1000 个套接字,通常少于 100 个,使用 I/O 完成端口增加的复杂性是否有任何真正的好处?

【问题讨论】:

当您不想提高速度和吞吐量时,请使用 ICOP。一个很好的描述在这里***.com/questions/754068/… 我已经决定,对于这个插件的第一个版本,每次test_cycle 迭代只轮询一次套接字会更快。然后可以根据实际场景对代码进行分析,并在必要时重新编写以使用 IOCP。我宁愿实施一个可以工作的第一个版本,也不愿强迫人们等待更长的时间来等待一个 IOCP 版本,它甚至可能不会(很多)更快。 【参考方案1】:

我认为你可以这样做: 1)建立一个监听线程。为每个连接发送一个套接字副本到线程池; 2) 建立线程池来处理请求;

我使用管道在线程之间进行传输,而不使用 I/O 完成端口,并且性能非常出色。

设置控制限制,确保资源不被耗尽。

【讨论】:

以上是关于用于小型单线程应用程序的 I/O 完成端口?的主要内容,如果未能解决你的问题,请参考以下文章

如何理解node是单线程异步I/O

WinSock 异步I/O模型-4

将多个 HTTP 请求等待同一个 I/O 完成端口

asyncio:Python异步编程模块

重叠 I/O:如何在完成端口事件或正常事件上唤醒线程?

asyncio:异步I/O事件循环和并发工具(持续跟新中)