Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java多线程,池的最佳大小取决于CPU内核(虚拟多线程和物理多线程)_Java_Multithreading_Cpu_Multicore - Fatal编程技术网

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

Java多线程,池的最佳大小取决于CPU内核(虚拟多线程和物理多线程),java,multithreading,cpu,multicore,Java,Multithreading,Cpu,Multicore,我正在玩Java中的multi-treading(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 Interrupted

我正在玩Java中的multi-treading(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())));

    }
}
公共类程序{
静态int-bestThreads=0;
静态长最佳时间=整数最大值;
公共静态void main(字符串[]args)引发InterruptedException、ExecutionException{
int cores=Runtime.getRuntime().availableProcessors();
对于(int-sizeOfPool=1;sizeOfPool-stop){
最佳时间=停止;
bestThreads=SizeOffool;
}
}
System.out.println(“池的最佳大小”+bestThreads+“结果为”+bestTime+“ms”);
}
公共静态类计算器实现可运行{
@凌驾
公开募捐{
doJob();
}
}
//因为我不想使用Thread.sleep(),所以这只会给我几毫秒的CPU负载
公共静态void doJob(){
对于(int j=0;j<1E3;j++){
Math.round(Math.sin(Math.sqrt(Math.random()));
}
}
当我运行这个程序时,我发现使用最少时间的设置是使用N个线程的设置,其中N通常是2(这意味着我应该使用2个线程作为线程池的大小)。 我不明白为什么会发生这种情况,因为我从.availableProcessors()获得的处理器数量是4(我使用的是i3多线程,它在笔记本电脑上,Windows显示运行程序时所有线程都处于活动状态)。 此外,当我改变所做的工作量时,我通常会得到不同的结果:

1E1->N=4

1E2->N=3或2

1E3->N=2

1E4->N=2

但即使在大多数情况下,我得到N=2

有人能解释一下为什么我会得到这样的结果,根据运行程序的CPU,通常建议的池大小是多少

下面是我觉得奇怪的一点输出:

在195个线程中完成了1000个任务//好的,这个处理器大约需要200毫秒才能完成,我想过多的计时会有所帮助

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

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

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

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

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

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

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

有时2,有时3的原因可能是由于多线程测试不是真正确定的(操作系统将不可避免地在随机时间消耗一些CPU)。此外,由于JIT的预热,短时间的测试通常会显示java中的很多变化(寻找微基准标记,这是一个复杂的主题)

不管怎样,您都应该看到i3/i7之间的差异。

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

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

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

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

有时2,有时3的原因可能是由于多线程测试不是真正确定的(操作系统将不可避免地在随机时间消耗一些CPU)。此外,由于JIT的预热,短时间的测试通常会显示java中的很多变化(寻找微基准标记,这是一个复杂的主题)


不管怎样,你都应该看到i3/i7之间的区别。

这个信息确实澄清了一些事情,所以谢谢你。因此,如果我在i7(真正的4核)上运行它,我应该得到4作为答案,对吗?Java中是否有API知道这一点?您是否有任何提示,为什么在较小的工作中会发生奇怪的事情,为什么我在2个和3个线程中得到几乎相同的结果。@PSIXO添加了一些解释此信息确实澄清了一些事情,所以谢谢您。因此,如果我在i7(真正的4核)上运行它,我应该得到4作为答案,对吗?Java中是否有API知道这一点?你知道为什么会有奇怪的事情吗