java - 对于数据报接收器来说,多少个线程比较合适?

标签 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

最佳答案

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

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

  • 一方面,如果没有足够的线程,可能会有未使用的硬件容量(核心),可以在高峰时间使用......但事实并非如此.

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

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

    如果线程太多,所有这些因素(以及相关的二阶效应)都会降低吞吐量……相对于最佳吞吐量。

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

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

最后,还有处理过载的问题。一方面,如果过载情况是暂时的,那么排队是一个合理的策略……前提是队列不会太深。另一方面,如果您预计过载会很常见,那么最好的策略是尽早放弃请求。

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

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

关于java - 对于数据报接收器来说,多少个线程比较合适?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26578692/

相关文章:

java - 线程上可运行对象的受监督调用

c - 如何为事件计时

python-3.x - Python3插槽无效- Graphite

java - 在哪里关闭这个 `input` 扫描器?

java - 功能标记与授权

java - 如何向不同的网络服务发送多个异步请求?

java - 解析 Web 服务响应时出现 MalformedURLException

c++ - 为什么不推荐使用 std::shared_ptr::unique() ?

ios - 在主 ui 线程中加载 Realm 对象是否可以接受?

javascript - 我在客户端和服务器端都实现了 xdomain 脚本,但在 IE9 中不断收到 'Timeout waiting on iframe socket' 警告