1

再描画が必要なオブジェクトが約 40000 個あります。そのほとんどは画面に表示されていないので、チェックを並行して行うことで多くの作業を省くことができたようです。しかし、CPU の使用率が 15% を超えることはないので、まだ 1 つのコアしか使用していないようです。スレッドを正しく実装しましたか? その場合、すべてのコアが使用されていないのはなぜですか? そして、すべてのコアを利用するより良い方法はありますか?

public void paintComponent(Graphics g)
{
    super.paintComponent(g);

    if (game.movables.size() > 10000)
    {
        final int size = game.drawables.size();
        final Graphics gg = g;
        Thread[] threads = new Thread[8];
        for (int j = 0; j < 8; ++j)
        {
            final int n = j;
            threads[j] = new Thread(new Runnable()
            {
                public void run()
                {
                    Drawable drawMe;
                    int start = (size / 8) * n;
                    int end = (size / 8) * (n + 1);
                    if (n == 8) end = game.drawables.size(); // incase size
                                                             // % 8 != 0
                    for (int i = start; i < end; ++i)
                    {
                        drawMe = game.drawables.get(i);
                        if (drawMe.isOnScreen())
                        {
                            synchronized (gg)
                            {
                                drawMe.draw(gg);
                            }
                        }
                    }
                }
            });
            threads[j].start();
        }

        try
        {
            for (int j = 0; j < 8; ++j)
                threads[j].join();
        }
        catch (InterruptedException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    else
    {
        for (Drawable drawMe : game.drawables)
        {
            if (drawMe.isOnScreen())
            {
                drawMe.draw(g);
            }
        }
    }
}
4

4 に答える 4

3

指摘されているように、synchronized (gg)はすべての図面を効果的にシリアル化しているため、スレッドの作成やその他のオーバーヘッドのために、シングルスレッドコードよりも遅くなる可能性があります。

しかし、私が書いている主な理由は、これがおそらくそうであるSwingがスレッドセーフではないということです。したがって、このプログラムの動作は悪い可能性があるだけでなく、未定義です。

このようなスレッドエラーは、いくつかのJavaランタイムパラメータといくつかのグラフィックスドライバを備えた一部のマシンでは厄介な動作として現れます。行ったことがある。それをしました。良くない。

JOGLを使用すると、レンダリングを高速化する最も確実な方法であるGPUに直接アクセスできます。

于 2012-07-18T04:33:05.190 に答える
1

これを正しく行うには、各 drawMe を (適切に同期された) リストに配置することから始め、結合が完了した後に実際にそれらをループで描画します。描画を高速化することはできません (drawMe の 99% をノックアウトした場合isOnScreen()は、必要な時間が大幅に短縮されます)。

ConcurrentLinkedQueueを使用すると、リストへの追加を同期する必要がなくなります。

次のステップでは、リストの代わりにブロッキング キューを使用して、描画コードを可視性チェックと並行して実行できるようにします。8 回のチェックが実行されているため、抽選に先んじることができます。(しかし、すべてのブロッキング キューは同期する必要があるか、それ自体で同期を行う必要があると思います。私はこれをスキップして、CLQ と最初のソリューションに固執します。よりシンプルで、おそらくより高速です。)

そして (Gene が指摘したように)、Swing に関連するすべてのものが EventQueue で開始されます。そこに置いておくか、人生がおかしくなるでしょう。UI を参照しない独自のコードのみをスレッドで実行する必要があります。

于 2012-07-18T20:00:12.690 に答える
0

画面外にあるオブジェクトをまだ描画していないので、上記で行っていることを実行しても、おそらくほとんど利益が得られません。

私はあなたがそれを悪化させていると言ってもいいでしょうが、それを導入synchronizeするのは遅く、またコンテキストスイッチを引き起こすスレッドを導入することは高価です。

パフォーマンスを向上させるには、JDKの一部であるJava2D描画ライブラリなどのさまざまな描画ライブラリの使用を検討する必要があります。http://java.sun.com/products/java-media/2D/index.jsp

于 2012-07-18T04:32:31.797 に答える
-1

Javaがこれをどのように処理するかはわかりませんが、他の言語は、あなたがやっているようにスコープを越えて何かを参照すると、恐ろしく爆発して死んでしまいますfinal int n(ループが停止するとスコープ外になるため)。実行可能なオブジェクトのフィールドにすることを検討してください。また、実際の作業をすべて実行しながら、グラフィックス オブジェクトを同期しています。これによる実際のパフォーマンスの向上は得られない可能性があります。オブジェクトが読み取り専用操作である画面上に並列にあるかどうかを明示的にチェックし、画面上のオブジェクトを他の種類のセットまたはコレクションに追加してから、順次レンダリングすることでメリットが得られる場合があります。

于 2012-07-18T04:09:35.117 に答える