我有一个方法可以并行计算列表中数字的平方并将它们相加:
public static double sumSquared(Listvalues) { return values .parallelStream() .mapToDouble(d -> d * d) .sum(); }
假设存在一些双重列表,如何进一步并行化,例如
double result = sumSquared(list0) + (sumSquared(list1) * sumSquared(list2));
有优雅的方式吗?我想为每个列表操作启动单独的线程并没有多大帮助,因为它们使用相同的线程池.是否有意义或是否应如上所述计算结果?
问题确实是即使sumSquared()
并行处理数据,每个sumSquared()
调用都是按顺序执行的.因此,这些列表仍然是逐个处理的,因此如果这些列表中的一些列表太小而无法分割到多个CPU,则会丢失CPU处理时间.
为避免这种情况,使用Java 8中的new CompletionStage
/ CompletableFuture
introduction 并行运行整个计算:
// each sumSquared() is submitted immediately to the common pool CompletionStagesumList0 = CompletableFuture.supplyAsync(() -> sumSquared(list0)); CompletionStage sumList1 = CompletableFuture.supplyAsync(() -> sumSquared(list1)); CompletionStage sumList2 = CompletableFuture.supplyAsync(() -> sumSquared(list2)); // as soon as sumList1 and sumList2 have both complete, their product is computed CompletionStage prodSumList1and2 = sumList1.thenCombine(sumList2, (a, b) -> a * b); // as soon as their product is computed and sumList0 is finished, the final sum is computed CompletionStage result = sumList0.thenCombine(prodSumList1and2, Double::sum); System.out.println(result.toCompletableFuture().get());
请注意,这使用公共池,默认情况下,该池使用所有CPU.因此,如果您只执行CPU繁重的操作,则使用自定义池可能无法提高性能,除非您有其他并行运行的作业.
例如,如果您的处理更多是I/O绑定或内存绑定,情况可能会有所不同.