我有一个基于a的ECHO服务器应用程序TCPListener.它接受客户端,读取数据并返回相同的数据.我使用async/await方法开发了它,使用XXXAsync框架提供的方法.
我设置了性能计数器来测量输入和输出的消息和字节数,以及连接的插槽数.
我创建了一个启动1400异步的测试应用程序TCPClient,并且每100-500ms发送一条1Kb消息.客户端在开始时有10-1000毫秒的随机等待启动,因此他们不会尝试同时连接所有客户端.我运作良好,我可以在PerfMonitor中看到1400连接,以良好的速率发送消息.我从另一台计算机上运行客户端应用程序 服务器的CPU和内存使用率非常低,它是带有8Gb RAM的Intel Core i7.客户端看起来比较忙,它是带有4Gb内存的i5,但仍然不是25%.
问题是如果我启动另一个客户端应用程序.连接在客户端中开始失败.我没有看到每秒消息的大幅增加(或多或少增加20%),但我看到连接客户端的数量大约是1900-2100,而不是预期的2800.性能略有下降,图表显示每秒最大和最小消息之间的差异比以前更大.
尽管如此,CPU使用率仍然不是40%,内存使用量仍然很少.我试图在客户端和服务器中增加数量或池线程:
ThreadPool.SetMaxThreads(5000, 5000);
ThreadPool.SetMinThreads(2000, 2000);
Run Code Online (Sandbox Code Playgroud)
在服务器中,循环接受连接:
while(true)
{
var client = await _server.AcceptTcpClientAsync();
HandleClientAsync(client);
}
Run Code Online (Sandbox Code Playgroud)
该HandleClientAsync函数返回a Task,但正如您所看到的循环不等待处理,只是继续接受另一个客户端.处理函数是这样的:
public async Task HandleClientAsync(TcpClient client)
{
while(ws.Connected && !_cancellation.IsCancellationRequested)
{
var msg = await ReadMessageAsync(client);
await WriteMessageAsync(client, msg);
}
}
Run Code Online (Sandbox Code Playgroud)
这两个函数只是异步读写流.
我看到我可以开始TCPListener指示backlog金额,但默认值是多少?
为什么可能是应用程序在达到最大CPU之前没有扩展的原因?
找出实际问题的方法和工具是什么?
UPDATE
我曾尝试Task.Yield和Task.Run办法,他们没有帮助.
服务器和客户端也在同一台计算机上本地运行.每秒增加客户端或消息量实际上会降低服务吞吐量.600个客户端每100ms发送一条消息,产生的吞吐量超过1000个客户端每100ms发送一条消息.
当连接超过~2000个客户端时,我在客户端看到的例外是两个.大约1500年我开始看到例外,但客户最终连接.超过1500我看到很多连接/断开:
"远程主机强行关闭现有连接"(System.Net.Sockets.SocketException)捕获到System.Net.Sockets.SocketException:"远程主机强行关闭现有连接"
"无法将数据写入传输连接:远程主机强制关闭现有连接." (System.IO.IOException)抛出System.IO.IOException:"无法将数据写入传输连接:远程主机强制关闭现有连接."
更新2
我已经使用async/await建立了一个非常简单的服务器和客户端项目,并按预期进行扩展.
我有可扩展性问题的项目就是 …