在每个线程的开销方面,ExecutorService是最轻量级的并行执行方法吗?

时间:2015-02-20 20:05:39

标签: java multithreading java-8 executorservice

对于在循环中重复执行多个相同计算任务的应用程序,ExecutorService是否是在开销方面在CPU之间分配任务的最合适的解决方案?

下面是我使用此答案https://stackoverflow.com/a/28632378/2721750构建的测试应用程序,以确定在2个英特尔酷睿i5 2.5 GHz物理内核上并行运行的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();
        }
    }
}

1 个答案:

答案 0 :(得分:1)

这取决于你想要做什么。

ExecutorService是执行独立,中等粒度任务的首选工具,具有自然的任务粒度(例如,为用户请求提供服务。)

相反,如果要执行细粒度协作任务,例如可并行化问题的递归分解所产生的任务,您可能需要ForkJoinPool

Java 8中的并行流使用ForkJoinPool来分解和执行流操作。如果您还不是并行专家,那么最好从并行流开始。