Java 多线程代码在某些进程上没有完全消耗内核

标签 java multithreading multicore

我有一些密集的处理代码,可以从文件中读取 block ,处理数据并以相同的顺序写入输出文件。一些数字:输入文件大约 29MB,输出文件大约 39MB,有 39461 个 block 。 单线程版本占用 100% 处理器(对于多核,仅使用一个内核)。

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

奔腾 4(1 核)2.8GHz 4302.407

英特尔至强(1 核)2.8GHz 3805.281

Intel E8300(2核)1773.062

Intel Q6600(4核)2202.231

英特尔 i5-4440(4 核)1300.127

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

有趣的是,额定值更高的 i7 在单线程中几乎与旧 E8300 一样快,但比 i5-4440 慢。

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

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

Intel E8300(2核)937.766

Intel Q6600(4核)657.515

英特尔 i5-4440(4 核)345.244

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

与单线程版本相比确实有所改进,但是:令我满意的是,任务管理器(Windows 上的所有系统)在除 i7 之外的所有进程/所有内核上都 100% 忙 - 这里它使用了所有 8 个线程,但每个线程仅使用了大约 40% ,结果反射(reflect)了这种行为。 i7 介于旧的 q6600 和新的(但额定值较低的)i5-4440 之间,更接近第一个。

一些说明:

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

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

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

在 Q6600 上进行了严格测试,证明 10 毫秒的 sleep 时间是最佳时间。 i5也提升的很好。 i7 不太好,所以我尝试了 sleep(3)、sleep(1)、sleep(0)。对于 3 毫秒,i7 运行了 529.782 次。 Sleep(0) 将繁忙百分比提高到大约。所有 8 个线程的 60% 和时间为 440.897。它更好,但还不够,因为我希望少于 200 秒,而且我认为如果我能实现更繁忙的处理器是可能的。

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

最佳答案

  1. 超线程显然不会线性扩展性能。你的 i7 有 4 个内核,而不是 8 个,并且在这些内核前面只有一些逻辑可以使上下文切换更快。与没有超线程的 4 核系统相比,您的性能预计最多只能提高 20-30%。

  2. 您在任务管理器中看到的内容并不直接反射(reflect)各个 Java 线程的效率,因为线程会在内核之间重新分配。相同的读数可以用少于 8 个线程来完成,每个线程都全速运行。

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

  4. 您应该尝试用依赖于 Phaser 的设计替换您的轮询循环。该类似乎非常适合您的用例。

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

关于Java 多线程代码在某些进程上没有完全消耗内核,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26039100/

相关文章:

java - 在 Java servlet 中处理之前发送响应

java - 如何在同一页面的java代码中获取jsp变量的含义?

android - 游戏开发用SurfaceView编程和线程策略

c# - 是否有一个有利于读者的 ReaderWriterLockSlim 等价物?

multithreading - Haskell 中的多核编程 - Control.Parallel

java - 用mockito模拟twilio

android:暂停一个 Activity 直到另一个 Activity 完成

python - 使用 python 和多处理压缩输出

c - 我如何判断我机器上的每个核心是否使用相同的计时器?

java - 如何对重复的对象列表进行排序