3

私はかなり単純なサーバーを持っています(kryonetを使用)。クライアントは、車の現在の状態(x、y、angleなど)のみを保存し、加速と方向転換の要求を送信しています。

サーバーはリクエストを受信し、物理スレッドがドレインして読み取り、更新するArrayBlockingQueueにリクエストを追加します。

別のプレーヤーを追加すると、ゲームの速度がほぼ2倍遅くなります。私は多くのことを除外しました(私はすべてのアップデートとパッケージ送信を60Hzで抑制しています)。

ブロッキングキューを使用すると、ブロッキングが多すぎて速度が低下しているのではないかと思います。

問題をブロックせずにクライアントリクエストを物理スレッドに送信するにはどうすればよいですか?

4

5 に答える 5

2

ブロッキング キューを使用するとブロックが多すぎて速度が低下していると思われます。

あなたは間違っていると思います。次のテスト プログラムは、ArrayBlockingQueue を介して 100 万個の整数をプッシュします。

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();
    }
}

私のラップトップでは、数秒で終了します。したがって、パフォーマンスのボトルネックがどこにあっても、必要以上に少なくとも 3 桁高いスループットを処理できるのは ArrayBlockingQueue ではありません。別の言い方をすれば、実行時間がまったくかからないスレッド通信アプローチを見つけたとしても、プログラムの速度はせいぜい 0.1% しか向上しないということです。

これと他のすべてのパフォーマンスの問題についての教訓: 既存のコードのパフォーマンスの問題に取り組むときの最初のステップは、通常、コードのどの部分が遅いかを測定することです。プロファイラーは、このタスクを大幅に簡素化します。

于 2011-11-07T17:58:30.683 に答える
1

キューを実装するためのロックフリー メカニズムであるディスラプタ (リング バッファ) を使用できます。見る:

于 2011-11-06T23:37:55.150 に答える
1

バグを発見しました。別の方法で物理シミュレーションを調整する必要がありました (world.step() 関数ではなく、呼び出される頻度を制限します)。こんな感じです。

while(true)
{
    delta = System.nanoTime() - timer;

    if(delta >= 16666666) // 60 Hz
    {
        world.step(1.0f, 6, 2);

        processAndUpdateYourData();

        timer = System.nanoTime();
    }
}

次に、この構成で自然に感じるように、すべての物理数値を調整する必要があります。

于 2011-11-08T15:26:24.033 に答える
0

あなたの質問は実装を前提としています-「なぜ私のコードはとても遅いのですか?」と尋ねるほうがよいでしょう。

ブロッキング キューは、プロデューサー/コンシューマー パターンを実装する最も効率的な方法です。

コンシューマ スレッドをさらに追加します。つまり、プロセッサ コアと同じ数のコンシューマ スレッドを追加してみてくださいRuntime.getRuntime().availableProcessors()

于 2011-11-06T23:37:48.513 に答える
0

すべてのクライアントを満足させるのに十分なスロットを使用してキューを作成していることを確認してください。クライアントが多すぎるためにキューがいっぱいになると、コマンドを挿入しようとするとブロックされます。それが問題でない場合は、物理 (消費者) スレッドが要求に追いついていないことを意味し、より多くの処理時間を確保する必要があります。

于 2011-11-06T23:54:43.700 に答える