Java 多线程性能

Java multithreading performance

所以我一直在研究 Java 中的线程并进行了测试。我制作了一个程序,可以进行大约 10^9 次乘法运算,然后打印出所需的毫秒数。

该程序有 2 种模式,其中一种不打印任何内容,只打印所需的毫秒数。然而,另一种模式在每次乘以数字时打印出 "It's done"。

在第一种模式下,1 个线程的结果很好,我得到了 8270 毫秒的结果,而当我使用 8 个线程时,我得到了 2237 毫秒的结果(我正在 8 核计算机上测试)。

然而,在第二种模式下,1 个线程的结果是 94 054 毫秒,8 个线程的结果是 96 430 毫秒。

我的问题是,为什么 8 个线程在第二种模式下的性能并不比 1 个更好?我猜这是因为你不能在终端同时打印 2 个东西,所以有一个问题,这就是原因,但这只是一个猜测。

I'm guessing it's something with that you can't print 2 things at the same time in the terminal so there is a que and that's the reason but that's just a guess.

是的。我不知道具体细节,这取决于您的打印方式(system.out.println 与日志库等),但无论您在做什么,代码都需要确保两个线程不写入同时,否则输出会出现乱码。所以肯定有某种互斥量、阻塞队列等被使用。这意味着当你添加更多的线程时,你并没有增加更多的并行性(因为它们都阻塞在同一个互斥锁上)但是你正在添加更多的锁争用所以更多的线程==更慢。

此类问题的关键分析工具是 Amdahl's Law,它根据严格串行的工作部分给出了并行性带来的加速上限。如果 n 是线程数,B 是严格串行工作的一部分,T(n) 是使用 n 个线程的时间:

T(n) = T(1)(B + (1-B)/n)

假设增加输出的大部分时间增加是连续的,我们得到 B 大约为 0.9。

T(8) = 94054(0.9 + 0.1/8)
     = 85824.275

这是时间的下限。实际上,8 个线程互相绊倒争夺同一个锁所浪费的时间与同一个小厨房里 8 个厨师做一道菜所浪费的时间差不多。