2

私は Java ForkJoin フレームワークを試していて、画像のピクセルをランダムな色に設定する簡単なテスト プログラムを作成しました。たとえば、疑似ノイズを生成します。

しかし、パフォーマンスをテストしているときに、実際には複数のスレッドで実行するよりもシングル スレッドで実行する方が高速であることがわかりました。高いしきい値を渡すことで、シングル スレッドで実行します。

これはクラス ワーカー クラスです。

public class Noise extends RecursiveAction {

    private BufferedImage image;
    private int xMin;
    private int yMin;
    private int xMax;
    private int yMax;
    private int threshold = 2000000; // max pixels per thread

    public Noise(BufferedImage image, int xMin, int yMin, int xMax, int yMax, int threshold) {
        this.image = image;
        this.xMin = xMin;
        this.yMin = yMin;
        this.xMax = xMax;
        this.yMax = yMax;
        this.threshold = threshold;
    }

    public Noise(BufferedImage image, int xMin, int yMin, int xMax, int yMax) {
        this.image = image;
        this.xMin = xMin;
        this.yMin = yMin;
        this.xMax = xMax;
        this.yMax = yMax;
    }

    @Override
    protected void compute() {
        int ppt = (xMax - xMin) * (yMax - yMin); // pixels pet thread
        if(ppt > threshold) {
            // split
            int verdeling = ((xMax - xMin) / 2) + xMin;
            invokeAll(new Noise(image, xMin, yMin, verdeling, yMax),
                    new Noise(image, verdeling+1, yMin, xMax, yMax));
        }
        else {
            // execute!
            computeDirectly(xMin, yMin, xMax, yMax);
        }
    }

    private void computeDirectly(int xMin, int yMin, int xMax, int yMax) {
        Random generator = new Random();
        for (int x = xMin; x < xMax; x++) {
            for (int y = yMin; y < yMax; y++) {
                //image.setPaint(new Color(generator.nextInt()));
                int rgb = generator.nextInt();
                int red = (rgb >> 16) & 0xFF;
                int green = (rgb >> 8) & 0xFF;
                int blue = rgb & 0xFF;

                red = (int) Math.round((Math.log(255L) / Math.log((double) red)) * 255);
                green = (int) Math.round((Math.log(255L) / Math.log((double) green)) * 255);
                blue = (int) Math.round((Math.log(255L) / Math.log((double) blue)) * 255);

                int rgbSat = red;
                rgbSat = (rgbSat << 8) + green;
                rgbSat = (rgbSat << 8) + blue;

                image.setRGB(x, y, rgbSat);
            }

        }
        Graphics2D g2D = image.createGraphics();
        g2D.setPaint(Color.RED);
        g2D.drawRect(xMin, yMin, xMax-xMin, yMax-yMin);
    }
}

6000 * 6000 のイメージを生成すると、結果は次のように なり
ます

マルチスレッド バージョンが遅いのはなぜですか?
これを修正するにはどうすればよいですか?

4

4 に答える 4

2

まず第一に、F/Jはニッチな製品です。巨大な配列がなく、DAGとして処理する場合は、間違った製品を使用しています。もちろん、F / Jは複数のプロセッサを利用できますが、F / Jのオーバーヘッドを一切かけずに、単純なマルチスレッドアプローチを使用することもできます。

4つのスレッドを使用してみて、それぞれに4分の1の作業を直接与えてください。

これは、F/Jが使用されることを意図した方法です。

Sum left  = new Sum(array, low, mid);
Sum right = new Sum(array, mid, high);
left.fork();
long rightAns = right.compute();
long leftAns   = left.join();
return leftAns + rightAns;

構造化された木の葉を歩かないと、すべての賭けが無効になります。

于 2012-12-22T14:28:47.080 に答える
1

Random の代わりに ThreadLocalRandom を使用したいと思います。

http://docs.oracle.com/javase/tutorial/essential/concurrency/threadlocalrandom.html

于 2013-04-10T17:47:54.647 に答える