【发布时间】:2017-02-08 14:20:47
【问题描述】:
我正在尝试检查以下代码的性能,但与 fork join 相比,每次我获得顺序操作时都会提供更好的性能。
我想找到最大整数的问题:
public class GetMaxIntegerProblem {
private final int[] intArray;
private int start;
private int end;
private int size;
public GetMaxIntegerProblem(int[] intArray, int start, int end) {
super();
this.intArray = intArray;
this.start = start;
this.end = end;
size = end - start;
}
public int getMaxSequentially() {
int max = Integer.MIN_VALUE;
for (int i = start; i < end; i++) {
int n = intArray[i];
max = n > max ? n : max;
}
return max;
}
public int getSize() {
return size;
}
public GetMaxIntegerProblem getMaxIntegerSubProblem(int subStart, int subEnd) {
return new GetMaxIntegerProblem(this.intArray, start + subStart, start + subEnd);
}
}
我的 fork join 操作:
import java.util.concurrent.RecursiveAction;
public class GetMaxIntegerAction extends RecursiveAction {
private final int threshold;
private final GetMaxIntegerProblem problem;
private int result;
public GetMaxIntegerAction(int threshold, GetMaxIntegerProblem problem) {
super();
this.threshold = threshold;
this.problem = problem;
}
@Override
protected void compute() {
if (problem.getSize() < threshold) {
result = problem.getMaxSequentially();
} else {
int midPoint = problem.getSize() / 2;
GetMaxIntegerProblem leftProblem = problem.getMaxIntegerSubProblem(0, midPoint);
GetMaxIntegerProblem rightProblem = problem.getMaxIntegerSubProblem(midPoint + 1, problem.getSize());
GetMaxIntegerAction left = new GetMaxIntegerAction(threshold, leftProblem);
GetMaxIntegerAction right = new GetMaxIntegerAction(threshold, rightProblem);
invokeAll(left, right);
result = Math.max(left.result, right.result);
}
}
}
我的主要测试程序:
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
public class GetMaxIntegerMain {
public GetMaxIntegerMain() {
// TODO Auto-generated constructor stub
}
private Random random = new Random();
private void fillRandomArray(int[] randomArray) {
for (int i = 0; i < randomArray.length; i++) {
randomArray[i] = random.nextInt(10000);
}
}
/**
* @param args
*/
public static void main(String[] args) {
GetMaxIntegerMain mainexcution=new GetMaxIntegerMain();
int arrayLength = 10_00_000;
int array[] = new int[arrayLength];
mainexcution.fillRandomArray(array);
GetMaxIntegerProblem problem=new GetMaxIntegerProblem(array, 0, array.length);
//No. of times sequential &
//Parallel operation should be performed to warm up HotSpot JVM
final int iterations = 10;
long start = System.nanoTime();
int maxSeq=0;
for (int i = 0; i < iterations; i++) {
maxSeq=problem.getMaxSequentially();
}
long endSeq=System.nanoTime();
long totalSeq=endSeq-start;
System.out.println(" time for seq "+(endSeq-start));
System.out.println("Number of processor available: " + Runtime.getRuntime().availableProcessors());
//Default parallelism level = Runtime.getRuntime().availableProcessors()
int threads=Runtime.getRuntime().availableProcessors();
ForkJoinPool fjpool = new ForkJoinPool(64);
long startParallel = System.nanoTime();
for (int i = 0; i < iterations; i++) {
GetMaxIntegerAction action=new GetMaxIntegerAction(5000, problem);
fjpool.invoke(action);
}
long endParallel = System.nanoTime();
long totalP=endParallel-startParallel;
System.out.println(" time for parallel "+totalP);
double speedup=(double)(totalSeq/totalP);
System.out.println(" speedup "+speedup);
System.out.println("Number of steals: " + fjpool.getStealCount() + "\n");
}
}
每次我运行这段代码时,我都会让 forkjoin 特定代码多花费 400% 的时间。我尝试了各种阈值组合,但我)没有成功。
我在 Windows 10 上的英特尔酷睿 i3 处理器 3.3 GHz 64 位上运行此代码。
如果有人能就这个问题提供一些指点,那将是非常有帮助的。
【问题讨论】:
-
您使用了不恰当的方式来评估性能。这应该是微基准测试。
-
new ForkJoinPool(64);?要么你是在骑着一头野兽,要么你误解了 FJP 的工作原理。 -
您拥有多少个内核,因为您不太可能获得良好的可扩展性。如果您的开销太高,我建议将您的问题分解为更大的工作,例如如果您有 2 个核心,请尝试将工作一分为二。
-
优化器可以多么容易地识别出您根本不使用结果。在顺序执行中,这要容易得多。无论如何,一百万个元素并不具有挑战性。而且,顺便说一句,事后将整数除法的结果转换为
double,不会以任何方式提高精度。
标签: java java-8 java-7 fork-join