我必须提高以下代码的性能,但我不知道要改进什么(或如何改进)。
目前,代码需要大约。创建94.478.400对象的12秒。
我想,我可以通过使用类似ForkJoinPool或ParallelArray之类的东西来加快速度,但是我不知道如何或在哪里将这种并行化放入我的代码中。
运行main-方法:
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class ParallelArray {
// class to hold the permutations
public static class Perm {
public Perm(double a, double b, double c) {
this.a = a;
this.b = b;
this.c = c;
}
double a;
double b;
double c;
public String toString() {
return "a=" + a + " b" + b + " c" + c;
}
}
public static void main(String[] args) {
var start = System.currentTimeMillis();
var perms = new ArrayList<Perm>();
// create first permutations
var perm1 = computePerm(2).collect(Collectors.toList());
// create second permutations
var perm2 = computePerm(-2).collect(Collectors.toList());
// now I permutate again with perm1 and perm2:
// iterating is fast
for (var p1 : perm1) {
for (var p2 : perm2) {
// but this operation needs too long
// can I speed this up by using fork-join or parallelArray?
perms.add(new Perm(p1.a + p2.a, p1.b + p2.b, p1.c + p2.c));
}
}
var end = System.currentTimeMillis();
// all the operations needs approx. 12 seconds
System.out.println("diff: " + (end - start) + " millis");
// it returns 94.478.400 objects
System.out.println("objects: " + perms.size());
}
public static Stream<Perm> computePerm(int inc) {
// I use a stream builder (to increase perfomance?)
Stream.Builder<Perm> all = Stream.builder();
// iterating is fast
for (var a : arrayA().toArray()) {
for (var b : arrayB().toArray()) {
for (var c : arrayC().toArray()) {
// but this operation needs too long
// can I speed this up by using fork-join or parallelArray?
all.add(new Perm(a + inc, b + inc, c + inc));
}
}
}
return all.build();
}
public static IntStream arrayA() {
return IntStream.rangeClosed(1, 30);
}
public static DoubleStream arrayB() {
return DoubleStream.iterate(0, d -> d + 0.1).limit(18);
}
public static DoubleStream arrayC() {
return DoubleStream.iterate(1, d -> d - 0.1).limit(18);
}
}编辑:
在玩完之后,我为computePerm(int )使用了另一种方法,它使用了parallelStream:
public static Stream<Perm> computePermParallel(int inc) {
Stream<Perm> all = arrayA().parallel().boxed().flatMap(a ->
{
return arrayB().parallel().boxed().flatMap(b ->
{
return arrayC().parallel().mapToObj(c ->
{
return new Perm(a + inc, b + inc, c + inc);
});
});
});
return all;
}然而,当使用computePermParallel(int inc)而不是computePerm(int inc)时,性能甚至更糟糕:而不是大约。12秒,我得等一下。19秒因此,即使有大量的对象,非并行版本也比并行版本快得多。不知道为什么。
发布于 2021-03-08 15:32:54
对代码的一些建议
var perms = new ArrayList<Perm>(94478400);来测试这一点。同样的方法可以通过在arraylist perms.ensureCapacity(94478400);上调用以下方法来实现ForkJoinPool:在您的场景中以并行方式运行并不会有任何帮助。如果你不得不做一些昂贵的计算,那会有帮助的。在您的示例中,只需创建一个新的Perm对象并将其放入perms列表中。最大的问题是ArrayList并不是线程安全的。像现在这样使用它会导致数据丢失。解决方案是让ForkJob返回完成后合并到完整列表中的临时列表。或者使用像CopyOnWriteArrayList这样的线程安全列表。这两种解决方案都会用数据创建更多的列表,并导致数据被复制。因此,与其改进运行时,它很可能会使其更加糟糕。发布于 2021-03-08 10:49:21
有几件事对你不利。
所以改变这个-
for (var a : arrayA().toArray()) {
for (var b : arrayB().toArray()) {
for (var c : arrayC().toArray()) { 为了这个-
final int[] aArray = arrayA().toArray();
final double[] bArray = arrayB().toArray();
final double[] cArray = arrayC().toArray();
for (var a : aArray) {
for (var b : bArray) {
for (var c : cArray) { 也许你会把它降低一个数量级--但我怀疑至少还有1到2秒--你使用了大量的内存--你真的需要这么做吗(这听起来像是这个案子的缺陷)?
为了让您了解内存与CPU的相对成本,您可以测试创建所有对象,然后循环并设置所有值和时间差。
https://stackoverflow.com/questions/66527737
复制相似问题