Java 并行化对数组中每个元素的递归函数调用(使用ForkJoinPool)
考虑以下场景:Java 并行化对数组中每个元素的递归函数调用(使用ForkJoinPool),java,arrays,multithreading,recursion,concurrency,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); rec
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);
...
}
public void processArray(int a,SomeType数组){
对于(int i=0;i
processArray对数组的每个元素调用recFunction。如何使用Java创建此程序的并行版本?请注意,要处理的数组可能非常大(最多10000个元素)。我的第一个想法是使用ForkJoinPool,但我绝对不能为每个数组元素创建RecursiveTask,因为这将创建10000个新对象
另外,我必须处理不同的数组,因此必须调用processArray几次。我希望避免每次创建新线程,而是使用现有线程。您知道如何使用Executor或ForkJoinPool实现吗?这是一个快速排序示例,无论如何都不是最优的,但应该为您提供与递归版本进行比较的基础
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;
}
}
}
}
import java.util.concurrent.ForkJoinPool;
导入java.util.concurrent.RecursiveAction;
公共类并行排序{
//默认情况下,创建并行度等于Runtime.availableProcessors()的ForkJoinPool
私有ForkJoinPool池=新的ForkJoinPool();
公共void排序(int[]元素){
invoke(新的排序(elements,0,elements.length-1));
}
公共类SortAction扩展了RecursiveAction{
私有静态最终长serialVersionUID=306042728856544983L;
最终int[]元素;
int低;
int高;
排序(int[]元素,int低位,int高位){
这个元素=元素;
这个.低=低;
这个高=高;
}
受保护的void compute(){
如果(低<高){
int pivotIndex=(低+高)>>>1;
数据透视索引=分区(数据透视索引);
invokeAll(新排序(元素,低位,数据透视索引-1),
新排序(元素,数据透视索引+1,高);
}
}
专用整型分区(整型数据透视索引){
int pivotValue=元素[pivotIndex];
交换(元素、数据透视索引、高);
int storeIndex=低;
对于(int i=低;i<高;i++){
if(元素[i]<数据透视值){
交换(元素、i、存储索引);
storeIndex++;
}
}
交换(元素、存储索引、高);
返回存储索引;
}
私有无效交换(int[]元素,int i,int j){
如果(i!=j){
int temp=元素[i];
元素[i]=元素[j];
元素[j]=温度;
}
}
}
}
一些简要说明:
- 您不需要在sort类中声明ForkJoinPool,我只是在这里这样做,以便调用方不必考虑池
- 一旦分区大小变小,这种快速排序如果返回到串行排序,性能会更好。我在这里不在乎这个
这在数百万个元素上运行没有问题。是否可以拆分阵列。例如,创建4个线程,每个线程计算数组的一半?还是元素相互依存?这项任务真的值得平行化吗?另外,我认为ForkJoinTask可以通过ForkJoinPool进行扩展。一个任务将创建多少个新任务?(可能是完成后的问题?)10k阵列太小,无法并行,10m是一个候选阵列。然后,按照JavaDoc中的示例分解数组。当达到阈值时,对大数组的一段调用ProcessArray(),并将结果连接到链上。@edharned:如果处理一个元素需要花费很多时间,则可以进行并行分析。@OP true。然后按照JavaDoc中的分解示例或StackOverflow上的许多示例进行操作。创建10k
RecursiveTask
对象的开销非常低,但是,其他注释是有效的:您不会使用单个元素(也就是说,您无论如何都会以1000个任务结束,每个任务处理10个元素左右),到目前为止,函数是递归的这一事实是否是使用fork-join池的原因还不清楚。您真的应该提到上面的源代码以及指向它的链接,@javadba Quicksort在所有算法书籍中都几乎相同(fork-joinpool示例也是如此)。另外要注意的是,如果你把一个LinkedList传给这个网站,那么这个网站的例子会在一个列表上排序,这是非常糟糕的。而且,如果你想学究的话,这些都是同样有影响力的:而且(你链接的作者显然遵循后者的伪代码,顺便说一句,一直到“storeIndex”的名字)