Java多线程,池的最佳大小,取决于CPU核心(虚拟多线程和物理)

时间:2014-07-09 14:34:05

标签: java multithreading cpu multicore

我正在玩Java中的多线程(Sun JDK 1.7 64位),试图更好地掌握一些概念。 我觉得令人费解的是找到执行程序的线程池的大小以及该设置对性能的影响。这是我的基本代码:

public class Program {

static int bestThreads = 0;
static long bestTime = Integer.MAX_VALUE;

public static void main(String[] args) throws InterruptedException, ExecutionException {

    int cores = Runtime.getRuntime().availableProcessors();

    for (int sizeOfPool = 1; sizeOfPool <= cores; sizeOfPool++) {
        ExecutorService exec = Executors.newFixedThreadPool(sizeOfPool);

        //System.out.println("Started");

        int noOftasks = 1000;
        for (int i = 0; i < noOftasks; i++) {
            Calculator c = new Calculator();
            exec.submit(c);
        }
        long start = System.currentTimeMillis();

        exec.shutdown();
        exec.awaitTermination(1000, TimeUnit.DAYS);

        long stop = (System.currentTimeMillis() - start);

        //System.out.println("Done " + noOftasks + " tasks in " + stop + " on " + sizeOfPool + " threads");

        if (bestTime > stop) {
            bestTime = stop;
            bestThreads = sizeOfPool;
        }

    }

    System.out.println("Best size of pool " + bestThreads + " result in " + bestTime + " ms");

}

public static class Calculator implements Runnable {

    @Override
    public void run() {
        doJob();
    }

}

//Can be whatever this just gives me a few milliseconds worth of CPU load since I don't want to use Thread.sleep()
public static void doJob() {
    for (int j = 0; j < 1E3; j++) {
        Math.round(Math.sin(Math.sqrt(Math.random())));

    }
}

当我运行这个程序时,我得到的是使用最少时间的设置是使用N个线程的设置,其中N通常为2(意味着我应该使用2个线程作为我的线程池的大小)。 我不明白为什么会发生这种情况,因为我从.availableProcessors()获得的处理器数量是4(我使用的是带有多线程的i3,它在笔记本电脑上,Windows显示所有线程在运行程序时都处于活动状态)。 当我改变完成的工作量时,我通常会得到不同的结果:

1E1 - &gt; N = 4

1E2 - &gt; N = 3或2

1E3 - &gt; N = 2

1E4 - &gt; N = 2

但即便如此,在大多数情况下,我得到N = 2;

有人可以解释为什么我会得到这样的结果以及通常建议的池大小,具体取决于程序运行的CPU。

这是一个我觉得很奇怪的输出:

在1个线程上完成1000个任务195 //这个处理器需要大约200毫秒来执行此操作,超频它将有助于我想象

在2个线程的134中完成1000个任务//我知道由于上下文切换和线程创建开销的一些其他影响我不能获得2倍的增加但是这是一个很好的加速

在3个线程上的138个中完成1000个任务//几乎与2个线程相同,为什么它不会更糟或更好

在4个线程的210中完成了1000个任务//更糟糕的是1个线程,这是我真的没有得到的

1 个答案:

答案 0 :(得分:4)

您的“测试”作业完全受CPU限制,这意味着它仅取决于 的CPU /核心速度。虽然i3声称拥有4个核心,但它是一个双核CPU(2核,每个核心有2个线程 - 也就是超线程)。

超线程不会为您提供4个完整内核,每个内核可以在其两个线程中的任何一个上运行(它会自动切换,例如,当线程等待内存访问时)。因此,在您的测试用例中,i3 CPU在两个线程中表现最佳,因为这是您的CPU可以同时处理(真正)的最大值。

使用不同的测试(例如,有大量内存访问或等待I / O),您将获得不同的“理想”线程数。

编辑:我无法区分java中真正的“物理”核心和“虚拟”核心。较新的AMD CPU在这方面有自己的怪癖(单独的内核,但FPU在2个内核之间共享),所以它真的是非常低级别的技术依赖。要真正获得所有细节,您可能需要读取CPU-Id并检查该CPU的数据表。

你得到某个时间2和有时3的原因可能是由于多线程测试不是真正确定的(操作系统将不可避免地随机吃掉一些CPU)。此外,由于JIT升温,短期测试显示java中存在很多变化(寻找微基准测试,这是一个复杂的主题)。

无论如何,你应该看到i3 / i7之间存在差异。