Java多线程代码不会完全消耗某些proc上的内核

时间:2014-09-25 12:49:38

标签: java multithreading multicore

我有一些密集的处理代码,它从文件中读取块,处理数据并写入输出文件IN THE SAME ORDER。一些数字:输入文件大约29MB,输出文件大约39MB,有39461块。 单线程版本需要100%处理器(对于多核仅使用一个核心)。

再一些数字(每个过程的秒数):

奔腾4(1核)2.8GHz 4302.407

Intel Xeon(1核心)2.8GHz 3805.281

Intel E8300(2核)1773.062

Intel Q6600(4核)2202.231

Intel i5-4440(4核)1300.127

i7-3632QM(4核,8线程)1412.191

有趣的是,更好的评级i7几乎与单线程中的旧E8300一样快,而且比i5-4440慢。

为了利用多核结构,我修改了代码。我启动了许多线程数等于核心(线程)的数量 - Runtime.getRuntime()。availableProcessors()。每个线程从文件读取并选取一个数字(synchronized块),进行密集处理,然后排队等待其选择的数字可用以便在输出文件中写入,写入并增加显示其编号的数字现在转到写入输出文件(也同步)。 代码工作正常,输出文件生成正确。

对于上述处理器(多核)我得到了这个:

Intel E8300(2核)937.766

Intel Q6600(4核)657.515

Intel i5-4440(4核)345.244

i7-3632QM(4核,8线程)584.346

改进确实与单线程版本相比,但是:任务管理器(Windows上的所有系统)让我满意地显示100%忙于除i7之外的所有进程/所有核心 - 这里它使用所有8个线程但每个只有大约40% ,结果反映了这种行为。 i7介于旧的q6600和新的(但评级较低的)i5-4440之间,接近第一个。

一些评论:

线程等待在输出文件中写入的方式是:

        while(ai.intValue() != outSeed.intValue()) {
            Thread.sleep(10);
        }

ai是从输入文件中读取的数字,现在等待轮到写入。 outSeed由成功写入的线程递增。

在Q6600上进行了强烈的测试,10毫秒的睡眠证明是最好的时间。 i5也改进得很好。 i7不太好,所以我试着睡觉(3),睡觉(1),睡觉(0)。 3分钟i7在529.782时间运行。睡眠(0)将忙碌百分比提高到约。所有8个线程和时间的60%是440.897。它更好,但它不够,因为我预期不到200秒,我认为如果我可以实现更繁忙的处理器是可能的。

同样,结果文件是预期的,除了i7-3632QM之外,行为是大多数过程(100%忙)的预期。你有什么建议?我从TaskManager尝试了setPriority = realTime,没有效果。 Op是否有可能。系统限制了proc的使用? 后来我可以访问六核Xeon并尝试使用它。 谢谢你的阅读。

3 个答案:

答案 0 :(得分:5)

  1. 超线程显然不会线性扩展性能。您的i7有4个内核,而不是8个内核,并且在这些内核之前只有一些逻辑,这使得上下文切换更快。在没有超线程的情况下,您只能期望比4核系统的性能提高20-30%。

  2. 您在任务管理器中看到的内容并未直接反映单个Java线程的效率,因为线程之间会重新分配线程。同样的读数可以用少于8个线程完成,每个线程全速运行。

  3. 你有8个线程而不是4个线程的事实可能会导致一些阻塞问题,因为你无法用工作提供所有8个线程。明确的sleep可能会影响这一点。

  4. 您应该尝试使用依赖Phaser的设计替换轮询循环。该课程似乎与您的用例完美匹配。

  5. Java 8中已经使用Streams API提供了您正在编码的内容。我最近写了一篇关于这个主题的post,它解释了如何使用Streams API来并行化任何基于I / O的源。您也可以尝试这种途径。

答案 1 :(得分:2)

您正在阅读和撰写文件。

有时您的应用程序将在I / O上被阻止,因此不会消耗CPU。

答案 2 :(得分:2)

在Marko和Claudio的评论之后,我又回到了测试阶段:

- @ Claudio我在i7中禁用HT并再次运行多核:忙70%/核心,结果略胜一筹(睡眠(0)):431.099

- @ Marko:我在启用HT的情况下再次在i7上运行单线程,并观察到java进程总数为13%,但是有8个忙的2个线程而不是大约40%的1个线程。这是操作系统干预,似乎以某种方式划分了线程上的工作。你的观察是正确的,我没有注意到i7上有第二个线程忙。

再次在E8300上,单线程总共50个忙,但两个核心的负载大约为50%。操作系统决定。多线程负载为90%。

- Q6600上的单个线程java进程有25%的cpu,但在图形视图中,所有内核都有一些加载(没有其他强烈的进程),所以操作系统以某种方式将单个线程划分到所有内核。多线程是90%。

@Steve C - 每个线程的速度更快i5应该有同样的问题。 i7系统上的i / o操作不应该比i5系统慢,因为它是相当新的

除了使用40%的i7之外所有触发器使用100%的印象现在正在减少,但仍希望从i7获得更多。也许使用Marko建议的内容会有所帮助。现在我对结果感到满意,但如果需要更少的时间,我会更改代码以查看差异。