Java多线程比单线程慢

时间:2018-02-21 09:18:03

标签: java multithreading

我正在测试在多个线程中运行代码时会发生什么。 这就是我正在做的事情:

1)使用我编写的名为" Matrix Generator"的Java程序,使用随机值生成50x50到1000x1000的不同矩阵大小。

2)运行另一个带有N个线程的Java程序,最多1到3个(我有一个四核计算机),其中每个线程使用Floyd Warshall algorythm计算矩阵的一致性。我没有将计算并行化。

我得到的结果是随着矩阵大小的增加,当我使用多线程时,执行时间会大大增加。使用单个线程时速度更快。请参阅下面的统计信息链接。

为什么会这样?是因为每个线程都启动自己的代码而CPU总线会导致瓶颈,因为每个线程都想访问RAM? 我使用了CPU分析器,我看到的是随着矩阵大小的增加,CPU缓存L2和缓存L3未命中率大幅增加,

这是Java代码:

public class MultiThreadGraphs {
public static void main(String[] args) {
    final int nFiles = 50;
    final int matrixSize;
    final int nThreads;

    Scanner reader = new Scanner(System.in);

    System.out.println("Enter matrix size: ");
    System.out.println("Available sizes: 50, 100, 150, 200, 300, 400, 500, 600, 1000");
    matrixSize = reader.nextInt();

    System.out.println("Enter n threads: ");
    nThreads = reader.nextInt();

    reader.close();

    System.out.println("Reading files..");

    List<int[][]> graphs = readFiles(matrixSize, nFiles);

    System.out.println("Total files: " + graphs.size());

    System.out.println("Running " + nThreads + " threads..");

    try {
        try {
            runThreads(graphs, nThreads);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static void runThreads(List<int[][]> graphs, int nThreads) throws InterruptedException, ExecutionException {

    ExecutorService executor = Executors.newFixedThreadPool(nThreads);
    Collection<Callable<Long>> callables = new ArrayList<Callable<Long>>();

    for(int i = 0; i < nThreads; i++) {
        callables.add(new Callable<Long>() {
            @Override
            public Long call() throws Exception {
                List<int[][]> callableGraphs = graphs;

                Instant start = Instant.now();

                for(int[][] graph: callableGraphs) {
                            FloydWarshall f = new FloydWarshall(graph);
                    f.checkConsistency();
                }

                Instant end = Instant.now();

                Duration timeElapsed = Duration.between(start, end);

                return timeElapsed.toNanos();
            }
        });
    }

    List<Future<Long>> futures = executor.invokeAll(callables);

    SummaryStatistics stats = new SummaryStatistics();

    for(Future<Long> future: futures) {
        stats.addValue(future.get());
    }


    String mean = String.valueOf(stats.getMean());
    double std = stats.getStandardDeviation();

    System.out.println("Execution time: " + (long)Double.parseDouble(mean));

    System.out.println("Mean: " + mean);
    System.out.println("Standard Deviation: " + std);

    executor.shutdown();
}
}

统计: https://docs.google.com/spreadsheets/d/1Wsgn14E9ltCWUHygC926xiz-vHEiENgSoHGzm_-BOa8/edit?usp=sharing

1 个答案:

答案 0 :(得分:0)

当你增加线程并提交给执行程序时,如果数字线程小于任务编号线程将轮询并且下一个任务将使用某种锁机制运行,则需要一些时间。

第二件事是所有任务都没有同时启动。一些任务将在获取线程后开始运行,并且你在这种情况下调用all all假设任务B先完成后跟任务C.但是任务A仍在继续。 for case的情况是等待任务A的结果可用,因为内部调用所有它正在进行future.get()。

要知道根据cpu核心大小创建简单线程的确切时间,并记录单个线程的时间,而不使用任何锁定或其他机制。或者,您可以使用ExecutorCompletionService获得第一个完整的任务时间。 / p>