我正在并行化一个非常复杂的程序以使其更快。为此,我大部分时间使用 ExecutorService。到目前为止,它运行得很好,但后来我注意到,仅仅一行代码就可以让我的程序运行速度减半。这是带有 exactScore.get()
的行。
我不知道为什么,但有时需要超过 0.1 秒才能获取 Future 对象的 double 值。
这是为什么呢?我该如何处理它运行得更快?有没有办法在多线程时直接在Double[]
中写入?
谢谢
int processors = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(processors);
// initialize output
Double[] presortedExScores = new Double[sortedHeuScores.length];
for(int i =0; i < sortedHeuScores.length; i++ ){
final int index = i;
final Collection<MolecularFormula> formulas_for_exact_method = multimap.get(sortedHeuScores[i]);
for (final MolecularFormula formula : formulas_for_exact_method){
Future<Double> exactScore = service.submit(new Callable<Double>() {
@Override
public Double call() throws Exception {
return getScore(computeTreeExactly(computeGraph(formula)));
}
});
presortedExScores[index] = exactScore.get();
}
}
最佳答案
这是可以预料的。那么它并不是“慢”,而是“慢”。它只是在做它的工作。
来自 get() 的 javadoc :
如有必要,等待计算完成,然后检索其结果。
长话短说:您似乎不理解代码中使用的概念。 future 的理念是它在 future 的某个时刻做事。
通过调用 get()
你可以表达:我不介意现在就等待,直到 Future“背后”的计算结果变得可用。
因此:你必须退后一步,再次查看你的代码;了解不同的“Activity 线索”如何真正发挥作用;以及他们如何/何时回到一起。
想到的一个想法:现在,您正在循环中创建 Future 对象;在创建 Future 后,立即对其调用 get()
。这完全违背了创建多个 Future 的想法。换句话说:而不是去:
foreach X
create future X.i
wait/get future X.i
你可以做类似的事情
foreach X
create future X.i
foreach X
wait/get for future X.i
换句话来说:让你的 future 真正并行地做事;而不是强制顺序处理。
如果这“不够”帮助,那么正如所说的:你必须审视你的整体设计,并确定是否有办法进一步“分解”事物。现在所有的 Activity 都“紧密地”一起发生;令人惊讶的是:当你同时做很多工作时,这需要时间。但正如您可能猜到的那样:这样的重新设计可能需要大量工作;如果不了解更多有关您的问题/代码库的信息,这几乎是不可能的。
更复杂的方法是,您编写代码,其中每个 Future 都有一种表达“我完成了”的方式 - 那么您将“仅”启动所有 Future;并等到最后一个回来。但正如所说;我无法在这里为您设计完整的解决方案。
这里另一个非常重要的要点:不要盲目地使用一些“碰巧”起作用的代码。编程的本质之一是理解源代码中使用的每个概念。 在运行代码并发现“哦,get()
使事情变慢”之前,您应该非常清楚代码在做什么。
关于java - ExecutorService Future::变得非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41684447/