简体   繁体   English

java中如何使用ForkJoinPool来使用多核?

[英]How to use ForkJoinPool to use multiple cores in java?

So I am trying to understand about how ForkJoinPool works.所以我试图了解 ForkJoinPool 是如何工作的。 I am trying to achieve better performance using this for a large array of about 2 million elements and then adding their reciprocal.我试图使用它来获得更好的性能,用于大约 200 万个元素的大型数组,然后添加它们的倒数。 I understand that ForkJoinPool.commpnPool().invoke(task);我知道 ForkJoinPool.commpnPool().invoke(task); calls compute() which forks the task in two tasks if it is not smaller and then computes and then joins them.调用计算(),如果任务不小,则将任务分叉为两个任务,然后计算然后加入它们。 So far, we are using two cores.到目前为止,我们使用了两个内核。

But if I want to xecute this on multiple cores, how do I do that and achieve 4 times better performance than the usual single thread run?但是,如果我想在多个内核上执行此操作,我该如何做到这一点并获得比通常的单线程运行高 4 倍的性能? Below is my code for default ForkJoinPool():下面是我的默认 ForkJoinPool() 代码:

@Override
        protected void compute() {
            // TODO
            if (endIndexExclusive - startIndexInclusive <= seq_count) {
                for (int i = startIndexInclusive; i < endIndexExclusive; i++)
                    value += 1 / input[i];
            } else {

                ReciprocalArraySumTask left = new ReciprocalArraySumTask(startIndexInclusive,
                        (endIndexExclusive + startIndexInclusive) / 2, input);
                ReciprocalArraySumTask right = new ReciprocalArraySumTask((endIndexExclusive + startIndexInclusive) / 2,
                        endIndexExclusive, input);
                left.fork();
                right.compute();
                left.join();
                value = left.value + right.value;
            }
        }
    }


protected static double parArraySum(final double[] input) {
        assert input.length % 2 == 0;

        double sum = 0;

        // Compute sum of reciprocals of array elements
        ReciprocalArraySumTask task = new ReciprocalArraySumTask(0, input.length, input);
        ForkJoinPool.commonPool().invoke(task);
        return task.getValue();
    }

//Here I am trying to achieve with 4 cores
protected static double parManyTaskArraySum(final double[] input,
                                                final int numTasks) {
        double sum = 0;
        System.out.println("Total tasks = " + numTasks);
        System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", String.valueOf(numTasks));
        // Compute sum of reciprocals of array elements
        int chunkSize = ReciprocalArraySum.getChunkSize(numTasks, input.length);
        System.out.println("Chunk size = " + chunkSize);
        ReciprocalArraySumTask task = new ReciprocalArraySumTask(0, input.length, input);
        ForkJoinPool pool = new ForkJoinPool();
//        pool.
        ForkJoinPool.commonPool().invoke(task);
        return task.getValue();
    }

You want to use 4 cores but you are giving a job which will need only two cores.您想使用 4 个内核,但您提供的工作只需要两个内核。 In the following example, getChunkStartInclusive and getChunkEndExclusive methods give the range for beginning and ending indexes of each chunk.在以下示例中,getChunkStartInclusive 和 getChunkEndExclusive 方法给出了每个块的开始和结束索引的范围。 I believe the following code can solve your problem and give you some implementation idea.我相信以下代码可以解决您的问题,并为您提供一些实现思路。

protected static double parManyTaskArraySum(final double[] input,
        final int numTasks) {
    double sum = 0;
    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", String.valueOf(numTasks));
    List<ReciprocalArraySumTask> ts = new ArrayList<ReciprocalArraySumTask>(numTasks);

    int i;
    for (i = 0; i < numTasks - 1 ; i++) {
        ts.add(new ReciprocalArraySumTask(getChunkStartInclusive(i,numTasks,input.length),getChunkEndExclusive(i,numTasks,input.length),input));
        ts.get(i).fork();
    }
    ts.add( new ReciprocalArraySumTask(getChunkStartInclusive(i, numTasks, input.length), getChunkEndExclusive(i, numTasks, input.length), input));
    ts.get(i).compute();

    for (int j = 0; j < numTasks - 1; j++) {
        ts.get(j).join();
    }

    for (int j = 0; j < numTasks; j++) {
        sum += ts.get(j).getValue();
    }
    return sum;
}

This is my approach:这是我的方法:

  • Threshold is the limit when the compute starts to calculate and stops to stack recursive calls, this works better if each processor is used twice or more (there is a limit of course), that's because I use numTask * 2 .阈值是计算开始计算和停止堆栈递归调用时的限制,如果每个处理器使用两次或更多次(当然有限制),这会numTask * 2 ,那是因为我使用numTask * 2

     protected static double parManyTaskArraySum(final double[] input, final int numTasks) { int start; int end; int size = input.length; int threshold = size / (numTasks * 2); List<ReciprocalArraySumTask> actions = new ArrayList<>(); for (int i = 0; i < numTasks; i++) { start = getChunkStartInclusive(i, numTasks, size); end = getChunkEndExclusive(i, numTasks, size); actions.add(new ReciprocalArraySumTask(start, end, input, threshold, I)); } ForkJoinTask.invokeAll(actions); return actions.stream().map(ReciprocalArraySumTask::getValue).reduce(new Double(0), Double::sum); }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM