ExecutorService无性能增益递归行列式Java
我读过类似的问题,其中问题是使用同步方法(如Math.random()),或者工作量太小,无法证明开销的合理性,但我认为这里的情况并非如此 我的处理器有4个物理/8个逻辑核。在一次预热后,我用n=1测试以下代码;2.3.4.11x11矩阵上的8个ExecutorService无性能增益递归行列式Java,java,multithreading,performance,recursion,executorservice,Java,Multithreading,Performance,Recursion,Executorservice,我读过类似的问题,其中问题是使用同步方法(如Math.random()),或者工作量太小,无法证明开销的合理性,但我认为这里的情况并非如此 我的处理器有4个物理/8个逻辑核。在一次预热后,我用n=1测试以下代码;2.3.4.11x11矩阵上的8个 ExecutorService pool = Executors.newFixedThreadPool(n); long startTime = System.currentTimeMillis(); double result = pool.subm
ExecutorService pool = Executors.newFixedThreadPool(n);
long startTime = System.currentTimeMillis();
double result = pool.submit(new Solver(pool, matrix)).get();
System.out.println(result);
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println(elapsedTime);
执行分别需要:
1~15500
2 ~ 13500 - 14000
3 ~ 14300 - 15500
4 ~ 14500 - 19000
8~19000-23000
所以我得到了一个
用2点来增加动力,
几乎没有增加3,
有时几乎没有提振,但有时极端减速,4
以8%的速度完成减速
代码如下:
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
public class Solver implements Callable<Double> {
private ExecutorService pool;
private double[][] matrix;
public Solver(ExecutorService pool, double[][] matrix){
this.pool = pool;
this.matrix = matrix;
}
public double determinant(double[][] matrix) {
if (matrix.length == 1)
return (matrix[0][0]);
double coefficient;
double sum = 0;
int threadsCount = ((ThreadPoolExecutor) pool).getMaximumPoolSize();
ArrayList<Double> coefficients = new ArrayList<Double>();
ArrayList<Future<Double>> delayedDeterminants = new ArrayList<Future<Double>>();
for (int k = 0; k < matrix.length; k++) {
double[][] smaller = new double[matrix.length - 1][matrix.length - 1];
for (int i = 1; i < matrix.length; i++) {
for (int j = 0; j < matrix.length; j++) {
if (j < k)
smaller[i - 1][j] = matrix[i][j];
else if (j > k)
smaller[i - 1][j - 1] = matrix[i][j];
}
}
coefficient = ((k % 2 == 0) ? 1 : -1) * matrix[0][k];
if (((ThreadPoolExecutor) pool).getActiveCount() < threadsCount
&& matrix.length > 5) {
coefficients.add(coefficient);
delayedDeterminants.add(pool.submit(new Solver(pool, smaller)));
} else
sum += coefficient * (determinant(smaller));
}
try {
for (int i = 0; i < coefficients.size(); i++)
sum += coefficients.get(i) * delayedDeterminants.get(i).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return (sum);
}
@Override
public Double call() throws Exception {
return determinant(matrix);
}
}
import java.util.ArrayList;
导入java.util.concurrent.Callable;
导入java.util.concurrent.ExecutionException;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Future;
导入java.util.concurrent.ThreadPoolExecutor;
公共类解算器实现了可调用{
私人服务池;
私有双[]矩阵;
公共解算器(ExecutorService池,双[]矩阵){
this.pool=pool;
这个矩阵=矩阵;
}
公共双行列式(双[]矩阵){
如果(矩阵长度==1)
返回(矩阵[0][0]);
双系数;
双和=0;
int threadscont=((ThreadPoolExecutor)pool.getMaximumPoolSize();
ArrayList系数=新的ArrayList();
ArrayList delayedDeterminants=新的ArrayList();
对于(int k=0;kk)
较小的[i-1][j-1]=矩阵[i][j];
}
}
系数=((k%2==0)?1:-1)*矩阵[0][k];
if(((ThreadPoolExecutor)pool).getActiveCount()5){
系数。加(系数);
delayedDeterminants.add(pool.submit)(新的求解器(pool,更小));
}否则
总和+=系数*(行列式(较小));
}
试一试{
对于(int i=0;i
处理这种分治算法的一般方法是在单个线程中降低到某一级别,直到有足够的独立任务,然后在ExecutorService上调度所有这些任务,让更多级别的递归在同一任务中执行。例如,在下一层中,您有121个子矩阵要计算其行列式,因此向ExecutorService提交121个任务。或者再上一层,获得12100个子问题并提交所有这些问题
轮询ExecutorService以获取活动任务计数可能不是最好的主意。创建一个newFixedThreadPool(4)
或您想要测试的任意数量的线程,并让ExecutorService管理任务的执行。如果您试图完成的是工作窃取,那么我强烈建议您花一些时间熟悉Fork/Join框架,它可以自动管理工作窃取。它被设计来精确地处理您的任务
另一件与问题没有直接关系的事情是:您必须重新设计代码,以便所有计算都只使用一个2D数组。1D数组会更好。处理这种分治算法的一般方法是在单个线程中降低到某个级别,直到有足够的独立任务,然后在ExecutorService上调度所有这些任务,让更多级别的递归在同一个任务中执行。例如,在下一层中,您有121个子矩阵要计算其行列式,因此向ExecutorService提交121个任务。或者再上一层,获得12100个子问题并提交所有这些问题 轮询ExecutorService以获取活动任务计数可能不是最好的主意。创建一个
newFixedThreadPool(4)
或您想要测试的任意数量的线程,并让ExecutorService管理任务的执行。如果您试图完成的是工作窃取,那么我强烈建议您花一些时间熟悉Fork/Join框架,它可以自动管理工作窃取。它被设计来精确地处理您的任务
另一件与问题没有直接关系的事情是:您必须重新设计代码,以便所有计算都只使用一个2D数组。1D阵列会更好。1&2)11x11是一个小矩阵,但计算量不小。该算法具有可怕的复杂性(类似于(n!)^2)。我用12x12矩阵试过,每次测试需要3分钟。100x100矩阵实际上需要数百年的时间。3) 不完全确定您的意思,如果是getActiveCount()行,那么想法是如果有空闲线程,我在线程中运行递归任务,否则我在当前线程中运行它。请注意,我不能总是在另一个线程中运行它,因为它是递归的,所以一个线程在其所有递归调用的线程都被调用之前是不会空闲的。@ndn啊,是的,现在它又回到我身边了。。。它确实在计算上爆炸了。处理这种分治算法的一般方法是在单个线程中下降到某个级别,直到有足够的独立任务,然后调度