以最小的开销并行执行来自相同 class 的方法
Executing methods from the same class in parallel with minimal overhead
我有一个 class 算法,它有 2 个复杂、耗时的方法,比如方法 1 和方法 2。我必须创建此 class 的多个实例,然后进行查询。方法 1 和方法 2 并行处理这些实例中的每一个。以下代码几乎实现了这一点:
private final List<Algorithm> algorithms;
private final ExecutorService executor;
private final List<Future<Void>> futures;
public AlgorithmManager(List<Algorithm> algorithms){
this.algorithms=algorithms;
//Define workers
executor = Executors.newFixedThreadPool(Constants.MAXTHREADS); //Creates a threat pool consisting of MAXTHREADS threats
futures=new ArrayList<Future<Void>>(algorithms.size());
}
/**
* Procedure to solve method1 for each algorithm in parallel
*/
public double[] solveMethod1(){
double[] results=new double[algorithms.size()];
List<FutureTask<Double>> taskList=new ArrayList<FutureTask<Double>>();
//submit all the relevant tasks to solve method1
for(Algorithm pp : algorithms){
FutureTask<Double> futureTask = new FutureTask<Double>(new Callable<Double>() {
@Override
public Double call() {
return pp.solveMethod1(); //SolveMethod1
}
});
taskList.add(futureTask);
executor.submit(futureTask);
}
//Query the results of each task one by one
for(int i=0; i<algorithms.size(); i++){
results[i]=taskList.get(i).get();
}
return results;
}
/**
* Procedure to solve method2 for each algorithm in parallel
*/
public int[] solveMethod2(){
int[] results=new double[algorithms.size()];
List<FutureTask<Integer>> taskList=new ArrayList<FutureTask<Integer>>();
//submit all the relevant tasks to solve method1
for(Algorithm pp : algorithms){
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() {
return pp.solveMethod2(); //SolveMethod2
}
});
taskList.add(futureTask);
executor.submit(futureTask);
}
//Query the results of each task one by one
for(int i=0; i<algorithms.size(); i++){
results[i]=taskList.get(i).get();
}
return results;
}
困扰我的是每次调用 solveMethod1 或 solveMethod2 时创建的所有 FutureTask 对象引起的开销(这种情况经常发生!)。问题是,根据 JavaDoc,您不能重用 FutureTask 对象,即我不能多次执行同一个 FutureTask,所以每次我想执行任何方法时都必须创建一个新的对象实例。
我考虑过使 class 算法可调用,从而添加一个方法:
@Override
public Double call() throws Exception {
return this.method1();
}
这样我可以简单地将算法实例提交给执行器,但我只能为一种方法这样做?
关于如何以干净高效的方式改进此实施的任何建议?不幸的是,将 method1 和 method2 放入 2 个不同的 classes 是不可取的,因为它们高度依赖于彼此的数据结构。
顺便说一句,这是一个简化的代码片段。在我的真实代码中,method1和method2也可以抛出异常。
开销可能很小,但您的代码因 FutureTasks 而不必要地复杂化。所以我建议您通过使用 Callables & Futures 来简化和清理您的代码。简而言之,您可以使用以下方法并将它们插入代码中的相关位置。
Callable<Double> c = new Callable<Double> () { ... };
Future<Double> f = executor.submit(c);
Double result = f.get();
我有一个 class 算法,它有 2 个复杂、耗时的方法,比如方法 1 和方法 2。我必须创建此 class 的多个实例,然后进行查询。方法 1 和方法 2 并行处理这些实例中的每一个。以下代码几乎实现了这一点:
private final List<Algorithm> algorithms;
private final ExecutorService executor;
private final List<Future<Void>> futures;
public AlgorithmManager(List<Algorithm> algorithms){
this.algorithms=algorithms;
//Define workers
executor = Executors.newFixedThreadPool(Constants.MAXTHREADS); //Creates a threat pool consisting of MAXTHREADS threats
futures=new ArrayList<Future<Void>>(algorithms.size());
}
/**
* Procedure to solve method1 for each algorithm in parallel
*/
public double[] solveMethod1(){
double[] results=new double[algorithms.size()];
List<FutureTask<Double>> taskList=new ArrayList<FutureTask<Double>>();
//submit all the relevant tasks to solve method1
for(Algorithm pp : algorithms){
FutureTask<Double> futureTask = new FutureTask<Double>(new Callable<Double>() {
@Override
public Double call() {
return pp.solveMethod1(); //SolveMethod1
}
});
taskList.add(futureTask);
executor.submit(futureTask);
}
//Query the results of each task one by one
for(int i=0; i<algorithms.size(); i++){
results[i]=taskList.get(i).get();
}
return results;
}
/**
* Procedure to solve method2 for each algorithm in parallel
*/
public int[] solveMethod2(){
int[] results=new double[algorithms.size()];
List<FutureTask<Integer>> taskList=new ArrayList<FutureTask<Integer>>();
//submit all the relevant tasks to solve method1
for(Algorithm pp : algorithms){
FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
@Override
public Integer call() {
return pp.solveMethod2(); //SolveMethod2
}
});
taskList.add(futureTask);
executor.submit(futureTask);
}
//Query the results of each task one by one
for(int i=0; i<algorithms.size(); i++){
results[i]=taskList.get(i).get();
}
return results;
}
困扰我的是每次调用 solveMethod1 或 solveMethod2 时创建的所有 FutureTask 对象引起的开销(这种情况经常发生!)。问题是,根据 JavaDoc,您不能重用 FutureTask 对象,即我不能多次执行同一个 FutureTask,所以每次我想执行任何方法时都必须创建一个新的对象实例。 我考虑过使 class 算法可调用,从而添加一个方法:
@Override
public Double call() throws Exception {
return this.method1();
}
这样我可以简单地将算法实例提交给执行器,但我只能为一种方法这样做? 关于如何以干净高效的方式改进此实施的任何建议?不幸的是,将 method1 和 method2 放入 2 个不同的 classes 是不可取的,因为它们高度依赖于彼此的数据结构。
顺便说一句,这是一个简化的代码片段。在我的真实代码中,method1和method2也可以抛出异常。
开销可能很小,但您的代码因 FutureTasks 而不必要地复杂化。所以我建议您通过使用 Callables & Futures 来简化和清理您的代码。简而言之,您可以使用以下方法并将它们插入代码中的相关位置。
Callable<Double> c = new Callable<Double> () { ... };
Future<Double> f = executor.submit(c);
Double result = f.get();