是否有正当理由不使用TcpListener来实现高性能/高吞吐量的TCP服务器而不是SocketAsyncEventArgs
我已经使用SocketAsyncEventArgs实现了这个高性能/高吞吐量的TCP服务器,使用一个大的预分配的byte数组和用于接受和接收的SocketAsyncEventArgs池来处理那些固定缓冲区,使用一些低级别的东西和闪亮的智能代码与一些TPL数据流和一些Rx组合在一起,它的工作非常完美;在这方面,几乎教科书--实际上,我从其他代码中学到了80%以上的这些东西。
然而,也存在一些问题和关切:
byte数组):使用SocketAsyncEventArgs,需要预先分配池。因此,对于处理100000个并发连接(更糟糕的情况,甚至在不同的端口上),大量的RAM是无用的;预先分配(即使在某些时候满足这些条件,服务器每天也应该能够处理1到2个这样的峰值)。TcpListener 实际上运行良好的:我实际上已经对TcpListener进行了测试(使用了一些技巧,比如在专用线程上使用AcceptTcpClient,而不是 async版本,然后将接受的连接发送到ConcurrentQueue,而不是创建Task的就地设置等),对于最新版本的.NET,它运行得非常好,几乎与SocketAsyncEventArgs一样好,没有数据丢失,内存脚打印也很低,这有助于避免服务器上浪费太多RAM,而且不需要预分配。那么,为什么我没有看到TcpListener在任何地方被使用,而每个人(包括我自己)都在使用SocketAsyncEventArgs呢?我是不是遗漏了什么?
发布于 2015-01-03 13:57:46
我没有看到任何证据表明这个问题是关于TcpListener的。您似乎只关心处理已被接受的连接的代码。这种连接是独立于侦听器的。
SocketAsyncEventArgs是一个CPU负载优化.我相信你可以用它达到更高的运算速度。与正常的APM/TAP异步IO的区别有多大?肯定还不到一个数量级。可能在1.2倍到3倍之间。上次对环回TCP事务速率进行基准测试时,我发现内核占用了CPU使用量的大约一半。这意味着你的应用程序可以获得最多2倍的速度,通过无限优化。
请记住,SocketAsyncEventArgs是在2000年左右的时候添加到BCL中的,那时CPU的能力要差得多。
只有在有证据表明需要使用SocketAsyncEventArgs时才使用它。它会使你效率低得多。更有可能滋生臭虫。
下面是套接字处理循环所需的模板:
while (ConnectionEstablished()) {
var someData = await ReadFromSocketAsync(socket);
await ProcessDataAsync(someData);
}非常简单的代码。由于await,没有回调。
如果您关心托管堆碎片:在启动时分配一个new byte[1024 * 1024]。当您希望从套接字读取时,请将单个字节读入此缓冲区的某个空闲部分。当单字节读取完成时,您将询问实际存在多少字节(Socket.Available),并同步提取其余的字节。这样,您只需插入一个相当小的缓冲区,仍然可以使用异步IO等待数据到达。
此技术不需要轮询。由于Socket.Available只能在没有从套接字读取的情况下增加,所以我们不会冒险执行太小的意外读取。
或者,您可以通过分配很少的大缓冲区和分发块来对抗托管堆碎片。
或者,如果你不认为这是一个问题,你不需要做任何事情。
https://stackoverflow.com/questions/27755330
复制相似问题