我写了这个Java方法,它需要大约一秒钟来运行(在我的计算机上):
/**
* This method takes about one second to run.
*/
private long eseguiUnitàDiLavoro() {
double x, y = 1000;
final long start_time, stop_time;
start_time = System.currentTimeMillis();
for (int i = 0; i < 20000000; i++) {
x = Math.random();
y = y / Math.atan(x);
}
stop_time = System.currentTimeMillis();
return stop_time - start_time;
}
如果我运行该方法五次(L0、L1、L2、L3、L4),得到以下时间:
- L0耗时1099毫秒,
- L1耗时1114毫秒,
- L2耗时1099毫秒,
- L3耗时1098毫秒,
- L4耗时1100毫秒。
总的执行时间是5510毫秒(大约是每个任务所用时间的5倍)。
但是如果我把这个方法构建成一个线程,并且运行它五次,我会得到以下时间:
- L0耗时15729毫秒,
- L1耗时15635毫秒,
- L2耗时15557毫秒,
- L3耗时15714毫秒,
- L4耗时15604毫秒。
现在,总执行时间为15745 ms。
任务执行顺序现在是L1 L2 L4 L3 L0,这是正确的。
但我预计这两种情况下的总体执行时间是一样的。相反,当使用多线程方法时,它比单线程方法慢大约三倍。
我原以为多线程方法比单线程方法稍慢(由于一些调度器开销),但是慢三倍对我来说太多了。
我还预计任务L0、L1、L2 ......每个都需要大约5秒,它们一起开始,也一起停止。事实上,它们一起开始,一起停止,但每个都需要大约15秒。
有人能给我解释一下为什么多线程处理效率如此之低吗?谢谢大家
1条答案
按热度按时间iqjalb3h1#
有很多可能的解释,包括您编写的多线程解决方案是错误的,但最让我吃惊的是
Math.random()
是完全同步的,不能并发运行,它的文档实际上是这样描述的:然而,如果许多线程需要以很高的速率生成伪随机数,则可以减少对每个线程具有其自己的伪随机数生成器的争用。
使用
ThreadLocalRandom
或单独的Random
对象代替Math.random()
可以解决这个问题。不过,一般来说,这可能与您的代码有关,而与多线程无关(我想到的其他可能性包括您如何测量时间消耗以及您的计算机上实际可用的内核数量)。