如何在不使用阻塞队列的情况下将消息传递给另一个线程?



我有一个非常直接的服务器(使用kryonet)。客户端只存储汽车的当前状态(x,y,角度等),并发送加速和转弯请求。

服务器正在接收请求,并将它们添加到ArrayBlockingQueue中,物理线程将其排出并读取和更新。

当添加另一个玩家时,游戏的速度减慢了几乎两倍。我已经排除了很多事情(我有所有的更新和包发送节流在60Hz。)

我怀疑使用阻塞队列阻塞太多,导致速度变慢。

如何将客户端请求发送到物理线程而不阻塞问题?

我怀疑使用阻塞队列阻塞太多,导致速度变慢。

你猜错了。下面的测试程序将100万个整数推入ArrayBlockingQueue:

public class ArrayBlockingQueuePerfTest {
    int maxi = 1000000;
    ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(1000,
            true);
    Thread sender = new Thread("sender") {
        public void run() {
            try {
                for (int i = 0; i < maxi; i++) {
                    queue.offer(i, 1, TimeUnit.SECONDS);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
    };
    Thread receiver = new Thread("receiver") {
        public void run() {
            try {
                int count = 0;
                long sum = 0;
                while (count < maxi) {
                    sum += queue.poll(1, TimeUnit.SECONDS);
                    count++;
                }
                System.out.println("done");
                System.out.println("expected sum: " + ((long) maxi) * (maxi - 1) / 2);
                System.out.println("actual sum:   " + sum);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
    };
    public ArrayBlockingQueuePerfTest() {
        sender.start();
        receiver.start();
    }
    public static void main(String[] args) {
        new ArrayBlockingQueuePerfTest();
    }
}

在我的笔记本电脑上,它会在几秒钟内终止。因此,无论您的性能瓶颈在哪里,它都不是ArrayBlockingQueue,它可以处理的吞吐量至少比您需要的高3个数量级。换句话说,即使您找到了一种完全不需要执行时间的线程通信方法,也只能将程序的速度提高至多0.1%。

从这个和所有其他性能问题中吸取教训:在处理现有代码中的任何性能问题时,第一步是测量代码的哪一部分慢,通常情况下,这不是预期的地方。

可以使用中断器(环缓冲区),这是一种实现队列的无锁机制。看到:

  • http://code.google.com/p/disruptor
  • http://martinfowler.com/articles/lmax.html

我发现了这个bug。我需要以不同的方式限制物理模拟(不是使用world.step()函数,而是限制调用的频率)。大概是这样的。

while(true)
{
    delta = System.nanoTime() - timer;
    if(delta >= 16666666) // 60 Hz
    {
        world.step(1.0f, 6, 2);
        processAndUpdateYourData();
        timer = System.nanoTime();
    }
}

然后我需要调整所有的物理数字,使他们感觉自然与这个配置。

你的问题以实现为前提-你最好问"为什么我的代码这么慢?"

阻塞队列是实现生产者/消费者模式最有效的方式。

我会添加更多的消费者线程-尝试添加尽可能多的消费者线程,因为有处理器内核-如Runtime.getRuntime().availableProcessors()

确保创建的队列有足够的可用插槽来满足所有客户机。如果队列因为客户端太多而满了,那么当尝试插入命令时,它们将阻塞。如果这不是问题,这意味着你的物理(消费者)线程跟不上请求,你需要确保它得到更多的处理时间。

相关内容

  • 没有找到相关文章

最新更新