2

JavaFX 8 プログラムに Point3D のストリームがあります。それらからメッシュを作成するために、代わりにそれらの (x、y、z) 座標のリストを生成できるようにしたいと思います。

これは、従来の Java ループによる単純なタスクです。(実際にはほとんど些細なことです。) しかし、将来的には、何万ものポイントを扱うことになるでしょう。Java Stream API を使用して、並列ストリームでこれを実現できるようにしたいと考えています。

私が探しているのは、この疑似コードとほぼ同等のものだと思います。

List<Double> coordinates = stream.parallel().map(s -> (s.getX(), s.getY(), s.getZ())).collect(Collectors.asList());

今のところ、そのような機能は見つかりませんでした。誰かが親切に私を正しい方向に押してくれませんか?

4

2 に答える 2

0

なんで?「数万ポイント」でも、コードは非常に短い時間で完了し、「並列ストリーム」では実際には何も得られません。

これは、時期尚早の最適化の完璧な例のように思えます。この場合、(まだ) 問題ではなく、問題になる可能性が低いもののコードを複雑にする可能性があります。

私の主張を証明するために、以下のテスト コードを作成しました。

GC 実行の影響を最小限に抑えるために、このコードを-Xms10g -Xmx10gで実行し、明示的な呼び出しを追加したgc()ので、テスト実行は「白紙の状態」で実行されました。

いつものように、パフォーマンス テストは JIT の最適化やその他の要因の影響を受けるため、ウォームアップ ループが用意されています。

public static void main(String[] args) {
    Random rnd = new Random();
    List<Point3D> input = new ArrayList<>();
    for (int i = 0; i < 10_000; i++)
        input.add(new Point3D(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble()));

    for (int i = 0; i < 100; i++) {
        test1(input);
        test2(input);
    }

    for (int i = 0; i < 10; i++) {
        long start1 = System.nanoTime();
        test1(input);
        long end1 = System.nanoTime();
        System.gc();
        long start2 = System.nanoTime();
        test2(input);
        long end2 = System.nanoTime();
        System.gc();
        System.out.printf("%.6f  %.6f%n", (end1 - start1) / 1_000_000d, (end2 - start2) / 1_000_000d);
    }
}
private static List<Double> test1(List<Point3D> input) {
    List<Double> list = new ArrayList<>();
    for (Point3D point : input) {
        list.add(point.getX());
        list.add(point.getY());
        list.add(point.getZ());
    }
    return list;
}
private static List<Double> test2(List<Point3D> input) {
    return input.stream().parallel()
                         .flatMap(s -> Stream.of(s.getX(), s.getY(), s.getZ()))
                         .collect(Collectors.toList());
}

結果

0.355267  0.392904
0.205576  0.260035
0.193601  0.232378
0.194740  0.290544
0.193601  0.238365
0.243497  0.276286
0.200728  0.243212
0.197022  0.240646
0.192175  0.239790
0.198162  0.279708

並列ストリームは少し遅いように見えますが、大きな違いはありません。また、10,000 ポイントの場合、0.3 ミリ秒未満
で完了することにも注意してください。 何でもありません!

カウントを 10,000 から 10,000,000 に増やしてみましょう (ウォームアップをスキップ):

433.716847  972.100743
260.662700  693.263850
250.699271  736.744653
250.486281  813.615375
249.722716  714.296997
254.704145  796.566859
254.713840  829.755767
253.368331  959.365322
255.016928  973.306254
256.072177  1047.562090

現在、並列ストリームの明確な劣化があります。3倍遅いです。これは、余分な GC 実行が原因である可能性があります。

結論: 時期尚早の最適化は良くない!!!!

あなたの場合、あなたは実際にそれを悪化させました。

于 2016-01-27T20:17:01.517 に答える