【问题标题】:Fork join not giving better performance分叉连接没有提供更好的性能
【发布时间】: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


【解决方案1】:

在很多情况下,您不应该期望在使用 fork join 时获得更好的性能,因为 fork 和 join 的开销可能会很大。例如看这个谈话(主要是下半场)https://www.youtube.com/watch?v=2nup6Oizpcw

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2011-07-23
    • 2011-01-11
    • 2014-05-12
    • 2018-05-18
    • 2011-07-20
    相关资源
    最近更新 更多