实施线程池后的 Tcp Server 性能问题
Tcp Server performance issues after implementing thread pool
我已经阅读了一些关于此事的讨论并设法理解了一点,但是在解决从 Thread class 转换为 ThreadPool class 时的性能问题时仍然存在一些问题
详情:
我已经构建了一个 tcp 服务器,用于教育目的(任务不应该使用异步方法),它接受客户端连接并为每个客户端创建一个新线程。使用这种方法,应用程序的执行时间不到一秒,但是当决定移动到线程池等下一级解决方案时,我的性能下降到 40-50 秒,只有 100 个客户端,我只发送一个 2048 字节的缓冲区,接收它并关闭。
前 12 个线程非常快,很可能是因为我的 cpu 是 6 核 12 线程,之后线程开始出现延迟。我对解决方案的想法和结构方法持开放态度。
服务器代码:
public void OnSocketReceive()
{
while (!this.exitServer)
{
if (!tcpListener.Pending())
{
Thread.Sleep(10);
continue;
}
TcpClient client = tcpListener.AcceptTcpClient();
IManageConnectedUser chatLogic = new ManageConnectedUser(connections, welcomeMessage);
//Thread clientThread = new Thread(new ParameterizedThreadStart(chatLogic.OnClientConnection));
//clientThread.Start(client);
ThreadPool.QueueUserWorkItem(chatLogic.OnClientConnection, client);
}
更多说明
到目前为止,根据我所做的调试和阅读的讨论,我得出的结论是问题出在 OnClientConnection 函数中的阻塞代码,更具体地说是在 stringCreateHandler 的内部函数中。我收到此错误的地方:System.Threading.ThreadInterruptedException:线程从第 39 行的等待状态中断,即 Thread.Sleep(10);
public string stringCreateHandler(TcpClient client)
{
StringBuilder sb = new StringBuilder();
try
{
do
{
if (client.Available > 0)
{
while (client.Available > 0)
{
char ch = (char)client.GetStream().ReadByte();
if (ch == '\r')
{
continue;
}
if (ch == '\n')
{
return sb.ToString();
}
sb.Append(ch);
}
}
Thread.Sleep(10);
} while (true);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
我检查了其余代码,我认为没有更多的阻塞代码,但我给项目 link https://github.com/nikolaymih/Chat-Project/tree/master/ChatProjectNewThreads
唯一的区别是 Thread class 而不是 ThreadPool 但这只是为了定位
查看您的完整项目,我认为您的问题是 OnClientConnection
很长-运行:在连接关闭之前它不会 return,因为这是一个“聊天应用程序”,连接保持打开状态,不会很快关闭。
如您所见,ThreadPool 从许多空闲线程开始,它会根据需要以大约每 500 毫秒一个的速率添加线程(尽管这是一个实现细节)。这通常不是问题:您不应该将 ThreadPool 用于非常长的 运行 任务,这些任务永远不会 return,并且永远占用线程。但是,由于您的 OnClientConnection
方法不会 return 多年,您只是在抢占 ThreadPool 线程,并迫使 ThreadPool 继续扩展。
如果您想为每个客户端使用一个线程,您最好为每个客户端创建一个新的 long-运行 线程。然而,这是非常浪费的:您将有大量的线程闲置而不做太多事情。最好有少量线程不断处理来自大量客户端的消息。可以自己构建它,但是使用 TcpListener
和 NetworkStream
.
的 async/await 功能要容易得多
我已经阅读了一些关于此事的讨论并设法理解了一点,但是在解决从 Thread class 转换为 ThreadPool class 时的性能问题时仍然存在一些问题
详情:
我已经构建了一个 tcp 服务器,用于教育目的(任务不应该使用异步方法),它接受客户端连接并为每个客户端创建一个新线程。使用这种方法,应用程序的执行时间不到一秒,但是当决定移动到线程池等下一级解决方案时,我的性能下降到 40-50 秒,只有 100 个客户端,我只发送一个 2048 字节的缓冲区,接收它并关闭。
前 12 个线程非常快,很可能是因为我的 cpu 是 6 核 12 线程,之后线程开始出现延迟。我对解决方案的想法和结构方法持开放态度。
服务器代码:
public void OnSocketReceive()
{
while (!this.exitServer)
{
if (!tcpListener.Pending())
{
Thread.Sleep(10);
continue;
}
TcpClient client = tcpListener.AcceptTcpClient();
IManageConnectedUser chatLogic = new ManageConnectedUser(connections, welcomeMessage);
//Thread clientThread = new Thread(new ParameterizedThreadStart(chatLogic.OnClientConnection));
//clientThread.Start(client);
ThreadPool.QueueUserWorkItem(chatLogic.OnClientConnection, client);
}
更多说明
到目前为止,根据我所做的调试和阅读的讨论,我得出的结论是问题出在 OnClientConnection 函数中的阻塞代码,更具体地说是在 stringCreateHandler 的内部函数中。我收到此错误的地方:System.Threading.ThreadInterruptedException:线程从第 39 行的等待状态中断,即 Thread.Sleep(10);
public string stringCreateHandler(TcpClient client)
{
StringBuilder sb = new StringBuilder();
try
{
do
{
if (client.Available > 0)
{
while (client.Available > 0)
{
char ch = (char)client.GetStream().ReadByte();
if (ch == '\r')
{
continue;
}
if (ch == '\n')
{
return sb.ToString();
}
sb.Append(ch);
}
}
Thread.Sleep(10);
} while (true);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
我检查了其余代码,我认为没有更多的阻塞代码,但我给项目 link https://github.com/nikolaymih/Chat-Project/tree/master/ChatProjectNewThreads 唯一的区别是 Thread class 而不是 ThreadPool 但这只是为了定位
查看您的完整项目,我认为您的问题是 OnClientConnection
很长-运行:在连接关闭之前它不会 return,因为这是一个“聊天应用程序”,连接保持打开状态,不会很快关闭。
如您所见,ThreadPool 从许多空闲线程开始,它会根据需要以大约每 500 毫秒一个的速率添加线程(尽管这是一个实现细节)。这通常不是问题:您不应该将 ThreadPool 用于非常长的 运行 任务,这些任务永远不会 return,并且永远占用线程。但是,由于您的 OnClientConnection
方法不会 return 多年,您只是在抢占 ThreadPool 线程,并迫使 ThreadPool 继续扩展。
如果您想为每个客户端使用一个线程,您最好为每个客户端创建一个新的 long-运行 线程。然而,这是非常浪费的:您将有大量的线程闲置而不做太多事情。最好有少量线程不断处理来自大量客户端的消息。可以自己构建它,但是使用 TcpListener
和 NetworkStream
.