简体   繁体   English

Java多线程比单线程慢

[英]Java Multi thread slower than single thread

I'm testing what happens when you run a code in multiple threads. 我正在测试在多个线程中运行代码时会发生什么。 Here's what I'm doing: 这是我在做什么:

1) Generate different matrix sizes from 50x50 to 1000x1000 with random values with a Java program I wrote called "Matrix Generator". 1)使用我编写的名为“矩阵生成器”的Java程序,生成具有随机值的50x50到1000x1000不同的矩阵大小。

2) Run another Java Program with N threads from 1 to 3 max (I have a quad core computer) where each thread calculate the Consistency of the matrix with Floyd Warshall algorythm. 2)运行另一个Java程序,该程序具有N个线程(最多1到3个)(我有四核计算机),其中每个线程都使用Floyd Warshall算法计算矩阵的一致性。 I don't parallelize the computation. 我不并行计算。

The result I get is that as the matrix size increases, the execution time increases considerably when I use multithreading. 我得到的结果是,随着矩阵大小的增加,当我使用多线程时,执行时间会大大增加。 It is faster when I use a single thread. 使用单线程时速度更快。 See the statistics link below. 请参阅下面的统计信息链接。

Why is this happening? 为什么会这样呢? Is it because each thread starts its own code and the CPU bus causes a bottleneck because every thread wants to access the RAM? 是因为每个线程都启动自己的代码,而CPU总线却因为每个线程都想要访问RAM而导致了瓶颈? I used a CPU profiler and what I saw Is that as the matrix size increases, the CPU cache L2 and cache L3 misses increase considerably, 我使用了一个CPU事件探查器,看到的是随着矩阵大小的增加,CPU缓存L2和缓存L3未命中率大大增加,

Here's the Java code: 这是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();
}
}

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

when you are increasing thread and submitting to executor it will take some time if number thread less than the task number as thread will poll and get next task will run using some lock mechanism. 当您增加线程并提交给执行者时,如果线程数小于任务编号,则将花费一些时间,因为线程将轮询并且获取下一个任务将使用某种锁定机制运行。

Second thing is all task not starting at same time .Some task will start running after getting thread and you are calling invoke all in that case Suppose task B finished first followed by task C. But task A was still going on.In that case for loop would be waiting for the result of task A to be available as inside invoke all it is doing future.get(). 第二件事是所有任务不是同时启动。某些任务将在获取线程后开始运行,并且在这种情况下您要调用全部调用假设任务B先完成,然后任务C.但是任务A仍在继续。循环将等待任务A的结果可用,因为内部调用了它正在执行的future.get()。

To know the exact time you can create simple thread depending upon cpu core size and note time taking by individual thread without using any lock or other mechanism.Or you can use ExecutorCompletionService to get first complete task time. 要知道确切的时间,您可以根据cpu核心大小创建简单的线程,并记录单个线程的时间而无需使用任何锁或其他机制。或者可以使用ExecutorCompletionService获取第一个完整的任务时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM