有多少线程对数据报接收器有用?

时间:2014-10-26 22:25:58

标签: java multithreading sockets udp datagram

我为我用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>
    }
}

Full receiving code

3 个答案:

答案 0 :(得分:2)

可能只有一个线程,假设你有一个DatagramSocket.你总是可以从你的线程中生成一个读取UDPSocket的processData线程。就像人们在评论中说的那样取决于你,但通常一个是好的。

编辑:

如果你这样做,也要考虑互斥锁。

答案 1 :(得分:1)

首先,任何使用数据报(例如UDP)进行通信的系统都必须能够处理丢弃的请求。他们会发生。您可以做的最好的事情是将典型的丢弃率降低到可接受的范围。但是你还需要认识到,如果你的应用程序无法处理丢失的数据报,那么它就不应该使用数据报。改为使用常规套接字。

现在讨论要使用多少线程的问题。答案是“它取决于”。

  • 一方面,如果您没有足够的线程,可能会有未使用的硬件容量(核心)可能在高峰时间使用...但不是

  • 如果您一次运行(或可运行)的线程太多,他们将在不同级别竞争资源:

    • 争夺CPU
    • 内存带宽竞争
    • 对锁和共享内存的争用。

    如果您的线程太多,所有这些事情(以及相关的二阶效应)都会降低吞吐量...相对于最优... ...

  • 如果您的请求处理涉及与其他计算机上的数据库或服务器通信,那么您需要足够的线程以在等待响应时允许其他事情发生。

根据经验,如果您的请求是独立的(对共享数据的争用最小)并且仅在内存中(没有数据库或外部服务请求),那么每个核心的一个工作线程是一个很好的起点。但是你需要准备好调整(也许重新调整)这个。

最后,存在处理过载的问题。一方面,如果过载情况是暂时的,那么排队是一种合理的策略......只要队列不会太深。另一方面,如果您预计过载是常见的,那么最好的策略是尽早放弃请求。

然而,存在次要问题。丢弃的请求可能需要客户注意到它在给定时间内没有得到回复,然后重新发送然后重新发送请求。这可能导致更严重的问题;即客户端在服务器实际丢弃请求之前重新发送请求...这可能导致同一请求被多次处理,并导致有效吞吐量的灾难性下降。

请注意,如果您有太多线程并且由于资源争用而陷入困境,则会发生同样的事情。

答案 2 :(得分:0)

似乎你对使用NginX或Apache的疑问有同样的疑问。你有没有读过有关NginX和10k的问题?如果没有阅读here。对于像这样的问题,没有“正确”的答案。正如其他伙伴强调的那样,这个问题是关于应用程序环境的需求(方面)。请记住,我们有很多web框架:每个框架都解决了提供html文档的相同问题,但使用不同的方式来完成任务。