我为我用java(和LWJGL)创建的游戏创建了一个发送 - 接收数据报系统。
然而,这些数据报经常被删除。那是因为服务器正在等待各种IO操作和其他处理在主循环中完成,而新的数据报正在发送给它(它显然没有收听)。
为了解决这个问题,我保留了我的主线程与捕获数据报的while true循环,但是我没有在主线程中进行处理,而是分支到不同的线程。
像这样:
ArrayList<RecieveThread> threads = new ArrayList<RecieveThread>();
public void run(){
while (true){
//System.out.println("Waiting!");
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, data.length);
try {
socket.receive(packet);
} catch (IOException e) {
e.printStackTrace();
}
//System.out.println("Recieved!");
String str = new String(packet.getData());
str = str.trim();
if (threads.size() < 50){
RecieveThread thr = new RecieveThread();
thr.packet = packet;
thr.str = str;
threads.add(thr);
thr.start();
}else{
boolean taskProcessed = false;
for (RecieveThread thr : threads){
if (!thr.nextTask){
thr.packet = packet;
thr.str = str;
thr.nextTask = true;
taskProcessed = true;
break;
}
}
if (!taskProcessed){
System.out.println("[Warning] All threads full! Defaulting to main thread!");
process(str, packet);
}
}
}
}
即为每个传入的数据报创建一个新线程,直到它达到50个数据包,此时它选择在一个等待下一个任务的现有线程中进行处理 - 如果所有线程都在处理,则默认为主线。
所以我的问题是:有多少线程是好的?我不想超载任何人的系统(相同的代码也将在玩家和客户端运行),但我也不想增加系统丢包。
另外,不同的线程甚至是个好主意吗?有没有人有更好的方法呢?
编辑:这是我的RecieveThread类(类是777行):
String str;
DatagramPacket packet;
boolean nextTask = true;
public void run(){
while (true){
////System.out.println("CLIENT: " + str);
//BeforeGame
while (!nextTask){
//Nothing
}
<Insert processing code here that you neither know about, nor care to know about, nor is relevant to the issue. Still, I pastebinned it below>
}
}
答案 0 :(得分:2)
可能只有一个线程,假设你有一个DatagramSocket.
你总是可以从你的线程中生成一个读取UDPSocket的processData线程。就像人们在评论中说的那样取决于你,但通常一个是好的。
编辑:
如果你这样做,也要考虑互斥锁。
答案 1 :(得分:1)
首先,任何使用数据报(例如UDP)进行通信的系统都必须能够处理丢弃的请求。他们会发生。您可以做的最好的事情是将典型的丢弃率降低到可接受的范围。但是你还需要认识到,如果你的应用程序无法处理丢失的数据报,那么它就不应该使用数据报。改为使用常规套接字。
现在讨论要使用多少线程的问题。答案是“它取决于”。
一方面,如果您没有足够的线程,可能会有未使用的硬件容量(核心)可能在高峰时间使用...但不是
如果您一次运行(或可运行)的线程太多,他们将在不同级别竞争资源:
如果您的线程太多,所有这些事情(以及相关的二阶效应)都会降低吞吐量...相对于最优... ...
如果您的请求处理涉及与其他计算机上的数据库或服务器通信,那么您需要足够的线程以在等待响应时允许其他事情发生。
根据经验,如果您的请求是独立的(对共享数据的争用最小)并且仅在内存中(没有数据库或外部服务请求),那么每个核心的一个工作线程是一个很好的起点。但是你需要准备好调整(也许重新调整)这个。
最后,存在处理过载的问题。一方面,如果过载情况是暂时的,那么排队是一种合理的策略......只要队列不会太深。另一方面,如果您预计过载是常见的,那么最好的策略是尽早放弃请求。
然而,存在次要问题。丢弃的请求可能需要客户注意到它在给定时间内没有得到回复,然后重新发送然后重新发送请求。这可能导致更严重的问题;即客户端在服务器实际丢弃请求之前重新发送请求...这可能导致同一请求被多次处理,并导致有效吞吐量的灾难性下降。
请注意,如果您有太多线程并且由于资源争用而陷入困境,则会发生同样的事情。
答案 2 :(得分:0)
似乎你对使用NginX或Apache的疑问有同样的疑问。你有没有读过有关NginX和10k的问题?如果没有阅读here。对于像这样的问题,没有“正确”的答案。正如其他伙伴强调的那样,这个问题是关于应用程序环境的需求(方面)。请记住,我们有很多web框架:每个框架都解决了提供html文档的相同问题,但使用不同的方式来完成任务。