对于一个在循环中重复执行多个相同计算任务的应用程序,ExecutorService是否是在CPU之间分配任务的最合适的解决方案?
下面是我使用这个答案构建的测试应用程序https://stackoverflow.com/a/28632378/2721750发现对于在Intel Core i5 2.5 GHz的2个物理核心上并行运行的2个任务,每个周期的开销约为0.1毫秒。
有没有其他解决方案可以帮助减少开销?
要求是任务需要接收一个参数,并向主线程返回一个值。它们是对所有权API的调用,我无法更改。
package asyncthreadbenchmark;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AsyncThreadBenchmark {
public static Double CalcResult(Integer p)
{
Long startTime = System.nanoTime();
double d = 0;
/* Simulating payload for the given number of milliseconds */
while ((System.nanoTime() - startTime) / 1000000 < p)
{
d = Math.PI * Math.pow(Math.log((double)p), Math.E);
}
return d;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
class CalcTask implements Callable<Double> {
Integer p;
CalcTask(Integer parameter) {
p = parameter;
}
@Override
public Double call() {
return CalcResult(p);
}
}
/*
Using Intel Core i5 2.5 GHz dual core, execuction of 10,000 cycles
with 6 ms per task max resulted in 61024-61034 ms total.
That is 0.1 ms overhead for 2 tasks per cycle.
If the savings from running 2 tasks in parallel exceed 0.1 ms
it makes sense to use Executor Service. Otherwise...
*/
ExecutorService executor = Executors.newFixedThreadPool(3);
try {
Integer param1, param2, param3;
param1 = 5;
param2 = 6;
// param3 = 4;
Future aFuture, bFuture, cFuture;
Double a, b, c;
Long startTime = System.nanoTime(), elapsed;
for (long i = 0; i< 10000; i++)
{
aFuture = executor.submit(new CalcTask(param1));
bFuture = executor.submit(new CalcTask(param2));
// cFuture = executor.submit(new CalcTask(param3));
try {
a = (Double)aFuture.get();
b = (Double)bFuture.get();
// c = (Double)cFuture.get();
} catch (InterruptedException | ExecutionException ex) {
// Logger.getLogger(AsyncThreadBenchmark.class.getName()).log(Level.SEVERE, null, ex);
}
}
elapsed = (System.nanoTime() - startTime) / 1000000;
System.out.println("Elapsed " + Long.toString(elapsed) + "ms");
}
finally {
executor.shutdown();
}
}
}
这取决于你想做什么。
ExecutorService
是执行独立的中等粒度任务的首选工具,这些任务具有自然的任务粒度(例如,为用户请求提供服务)
相反,如果您希望执行细粒度的协作任务,例如那些由可并行化问题的递归分解产生的任务,那么您可能需要ForkJoinPool
。
Java 8中的并行流使用ForkJoinPool
来分解和执行流操作。如果您还不是并行方面的专家,那么最好从并行流开始。