我有一个计算n体问题的Java程序。在每次迭代中,它检查每个身体施加在每个其他身体上的力,然后根据力量移动它们。
身体始终在同一个地方开始(我将它们排列成一个圆圈,从身体0到身体n),它们总是以相同的顺序(从身体0到n)进行检查和移动。但是,当我运行程序30次时,我的运行时间会大不相同。一个运行时间为2,947,188毫秒(49分钟),而另一个运行时间为920,967毫秒(15分钟)。我对这些时间的数量级并不感到惊讶,因为我在很多身体上使用蛮力方法(O(n ^ 2))。但我想知道为什么确定性算法存在这样的差异?如果算法时间相同,那么运行时间是否应该相同(或至少接近)?
在你问之前,是的,我正在测量计算线程的时间,而不是挂钟时间。
编辑 - 我正在测量这样的时间:
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long startUserTimeNano = bean.getCurrentThreadCpuTime();
// ... Code to do the stuff...
double taskUserTimeNano = (bean.getCurrentThreadCpuTime() - startUserTimeNano);
CPUmillisecondsElapsed += taskUserTimeNano/1000000.0;
这是否会测量除计算步骤以外的任何其他内容?
第二次修改 - 现在我将其更改为测量时间,如下所示:
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long startUserTimeNano = bean.getCurrentThreadUserTime();
// ... Code to do the stuff...
double taskUserTimeNano = (bean.getCurrentThreadUserTime() - startUserTimeNano);
CPUmillisecondsElapsed += taskUserTimeNano/1000000.0;
然而,结果仍然不可重复。我还尝试使用标志-Xint运行我的程序,结果仍然不可重复。
假设问题在算法和多线程中是否安全?或者它仍然是一个与Java有关的问题?
答案 0 :(得分:1)
您确定正确测量时间吗?在jvm中可能有许多线程作为用户不可见。如果你得到系统时间,那么你忽略了那些线程的存在。此外,如果您正在运行任何其他线程,则可能忽略了它们添加的时间。
答案 1 :(得分:1)
由于动态编译,垃圾收集和自适应优化,对多线程程序进行基准测试可能具有挑战性。我建议阅读Brian Goetz的“Java Concurrency in Practice”第12章。
答案 2 :(得分:0)
假设您正在计时的线程只是众多线程中的一个,那么简单地在线程中获取计算的开始和结束时间的差异实际上并不是测量线程所花费的实际CPU时间。它与其他线程竞争,并且必须在其他线程运行时暂停/等待,但你也会计算它等待的时间。
由于调度线程的方式可能会有所不同,我们也必须考虑垃圾收集,从开始到完成线程所需的总时间可能会有很大差异。但实际所需的CPU时间不会有所不同。
修改强>:
我认为您需要衡量的是线程在用户模式下花费的时间。这应该消除等待OS / JVM所花费的时间,并且只测量在线程中运行所花费的时间。因此,请尝试使用getCurrentThreadUserTime
。
我找到了一个早期的SO帖子:Difference between thread user time and thread cpu time in Java