并行化对数组的每个元素的递归函数调用(使用ForkJoinPool)

时间:2014-06-18 21:42:17

标签: java arrays multithreading recursion concurrency

考虑以下情况:

public void processArray(int a, SomeType array) {
    for (int i = 0; i < array.length; ++i) {
        recFunction(a, array[i]);
    }
}
private void recFunction(int a, SomeType element){
     ...
     recFunction(a + x, element);
     recFunction(a + y, element);
     ...
}

processArray在数组的每个元素上调用recFunction。我怎么能用Java创建这个程序的并行版本?请注意,要处理的数组可能非常大(最多10,000个元素)。我的第一个想法是使用ForkJoinPool,但我绝对不能为每个数组元素创建一个RecursiveTask,因为这将创建10,000个新对象。

另外,我将不得不处理不同的数组,因此必须多次调用processArray。我想避免每次创建新线程并使用现有线程。任何想法如何使用Executor或ForkJoinPool实现它?

1 个答案:

答案 0 :(得分:0)

这是一个快速排序示例,无论如何都不是最优的,但应该为您提供与递归版本进行比较的基础。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

public class ParallelSort {
    // default, Creates a ForkJoinPool with parallelism equal to Runtime.availableProcessors()
    private ForkJoinPool pool = new ForkJoinPool();

    public void sort(int[] elements) {
        pool.invoke(new SortAction(elements, 0, elements.length-1));
    }

    public class SortAction extends RecursiveAction {
        private static final long serialVersionUID = 3060427288506544983L;

        final int[] elements;
        int low;
        int high;

        SortAction(int[] elements, int low, int high) {
            this.elements = elements;
            this.low = low;
            this.high = high;
        }

        protected void compute() {
            if (low < high) {
                int pivotIndex = (low + high) >>> 1;
                pivotIndex = partition(pivotIndex);

                invokeAll(new SortAction(elements, low, pivotIndex - 1),
                          new SortAction(elements, pivotIndex + 1, high));
            }
        }

        private int partition(int pivotIndex) {
            int pivotValue = elements[pivotIndex];

            swap(elements, pivotIndex, high);
            int storeIndex = low;

            for (int i = low; i < high; i++) {
                if (elements[i] < pivotValue) {
                    swap(elements, i, storeIndex);
                    storeIndex++;
                }
            }

            swap(elements, storeIndex, high);
            return storeIndex;
        }

        private void swap(int[] elements, int i, int j) {
            if (i != j) {
                int temp = elements[i];
                elements[i] = elements[j];
                elements[j] = temp;
            }
        }
    }
}

一些快速说明:

  • 你没有需要在你的排序类中声明ForkJoinPool,我只是在这里做了,所以调用者不必考虑池。 / p>

  • 如果分区大小很小,那么这种快速排序可以更好地恢复到串行排序。我没有在这里烦恼。

在数百万个元素上运行没有问题。