【问题标题】:Java multi-threading, best size for a pool depending on CPU cores (virtual with multi-threading and physical)Java 多线程,池的最佳大小取决于 CPU 内核(虚拟多线程和物理)
【发布时间】:2014-07-09 14:34:05
【问题描述】:

我正在玩 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 -> N=4

1E2 -> N=3 或 2

1E3 -> N=2

1E4 -> N=2

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

谁能解释一下为什么我会得到这样的结果,以及通常建议的池大小取决于程序运行的 CPU。

这里还有一些我觉得奇怪的输出:

在 1 个线程上完成 195 个任务 1000 个任务//好吧,这个处理器需要大约 200 毫秒才能完成这项工作,我想超频会有所帮助

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

在3个线程上完成138个任务1000个//几乎和2个线程一样,为什么没有更糟或更好

在 210 个线程上完成 1000 个任务,4 个线程//比 1 个线程更糟糕,这是我真的不明白的一个

【问题讨论】:

    标签: java multithreading cpu multicore


    【解决方案1】:

    您的“测试”作业完全受 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 之间的区别。

    【讨论】:

    • 此信息确实有点说明问题,所以谢谢。所以如果我在 i7(真正的 4 核)上运行它,我应该得到 4 作为答案,对吗? Java中是否还有API可以以某种方式知道这一点?您是否有任何暗示为什么较小的工作会发生奇怪的事情以及为什么我在 2 和 3 线程上得到几乎相同的结果。
    • @PSIXO 添加了一些解释
    猜你喜欢
    • 2014-04-12
    • 2012-10-08
    • 1970-01-01
    • 1970-01-01
    • 2022-12-29
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    相关资源
    最近更新 更多