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

4

您可以使用flatMap

List<Double> coordinates = 
    stream.parallel()
          .flatMap(s -> Stream.of(s.getX(), s.getY(), s.getZ()))
          .collect(Collectors.asList());
于 2016-01-27T19:30:53.077 回答
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

没有大的区别,虽然并行流看起来稍微慢一些。
另请注意,它在不到 0.3 ms的时间内完成,获得 10,000 个点。
没什么!

让我们尝试将计数从 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 回答