【问题标题】:Overhead of thread creation and deletion v/s unused threads线程创建和删除与未使用线程的开销
【发布时间】:2013-04-27 04:54:13
【问题描述】:
为了开发一个可以同时处理最多“x”个客户端的 udp 服务器,我有两个选择:
服务器启动后,立即创建“x”线程,无需检查是否所有“x”客户端都处于活动状态。
第二个选项是,当服务器启动时,它会等待客户端的请求,当来自特定客户端的请求到达时,才会生成一个线程来为该客户端提供服务。
如果特定客户端出现故障,则专用于该特定客户端的线程也会被删除。
在选项#1 中,即使只有 1 个客户端连接,在开始时也会创建“x”个线程,仅当线程将被使用并且所有剩余的“x-1”个线程将被挂起。
在选项#2 中,我似乎将面临连续创建和删除线程的开销。
我决定使用选项#2 来实现我的应用程序,但我仍然对我的选择是否正确感到困惑。
如果我错了,请帮助我。
【问题讨论】:
标签:
c
windows
multithreading
【解决方案1】:
通过实现线程池来结合使用两者。创建一个最初为空的线程池,或者包含许多初始挂起的线程,由您选择。当新客户端“连接”并且未超过允许的最大客户端数时,检查池是否有可用线程。如果是这样,请重新使用它。如果没有,请创建一个新线程。当客户端“断开连接”时,将线程放回池中并挂起。如果给定线程在池中停留了一段时间,请将其移除并销毁。
【解决方案2】:
考虑线程运行时上下文切换的开销。在四核 CPU 上使用三千个线程将比在同一个四核 CPU 上使用四到八个线程带来更多的开销。考虑一下 3000 个线程将使用的资源,就堆栈分配而言,与 4 到 8 个线程相比。
在静态、预定或用户可配置数量的线程上处理尽可能多的非阻塞套接字会更有意义。
【解决方案3】:
选项 3 - 可以根据需要增加和减少的线程池,理想情况下,完全不增加。
【解决方案4】:
您所说的内容有点混乱,或者可能需要更多信息。请记住,UDP 客户端不连接它们只是发送数据包,并且不能保证这些数据包按发送顺序到达。
我要做的只是让一个监听 UDP 套接字等待数据包。您应该通过其 IP 地址或任何其他方法(例如数据包数据中的 ID)维护有效客户端的列表。收到数据包后,您可以使用处理客户端请求的函数/线程对其进行处理。正如我所看到的,您甚至不需要启动新线程,但这取决于服务器在收到数据包时要做什么以及处理它需要多长时间。另外,请记住处理请求的函数/线程不能从客户端(通过同一端口)接收更多数据包;所有传入的数据包都由服务器线程处理。处理客户端请求的函数或线程它所能做的就是向客户端发送一个或多个 UDP 数据包以确认请求,但它无法与客户端保持对话,也无法确定客户端是否关闭,因为有没有永久开放的连接。如果您需要在服务器和客户端之间进行对话,则需要更改为 TCP 套接字。
这是代码草稿:
ClientRequestThread(DatagramPacket packet)
{
String FromIP = packet.getAddress().getHostAddress();
byte[] data = packet.getData();
// Here you must identify the client, either by its IP address
// or maybe an ID inside the data.
if (TheDataHaveBeenProccessOK)
{
Send a positive acknowledge
}
else
{
Send a negative acknowledge
}
}
ServerThread()
{
DatagramSocket datagramSocket;
try
{
datagramSocket = new DatagramSocket(MyPortNumber);
}
catch (Exception e)
{
// Unable to open the datagram socket.
// Handle it accordingly
return;
}
byte[] buffer = new byte[256]; // change it to your needs
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (YouDontStopMe)
{
try
{
datagramSocket.receive(packet);
// Here you must either call a function or start a thread
// to handle the client request
// depends on what you are going to do with the client's request.
ClientRequestThread(packet);
}
catch (Exception e)
{
// Error reading the socket, handle it accordingly
e.printStackTrace();
}
}
datagramSocket.close();
}