在Java中需要多长时间? 用Java测量延迟时间

我不想更改此代码,我只对JVM,OS或内核定制/配置感兴趣以获得最佳结果!


我有一个第二个循环(1000 x 1ms)

public static void main(String[] args) throws InterruptedException { long start = System.nanoTime(); for (int i = 0; i < 1000; i++ ) { Thread.sleep(TimeUnit.MILLISECONDS.toMillis(1)); } long duration = System.nanoTime() - start; System.out.println("Loop duration " + duration / TimeUnit.MILLISECONDS.toNanos(1) + " ms."); } 

在我的带有内核3.12的Fedora 20上,这个循环需要1055毫秒。

这是相当不错的结果,平均超过1100ms

是否可以使用自定义JVM标志或操作系统配置使此代码更快?

 Loop duration 1055 ms. 

调用sleep()你基本上告诉操作系统暂停你的线程至少X毫秒。 无法保证在此时间之后它将继续执行,否则操作系统将在稍后重新构建您的线程。 此外,最小sleep时间及其准确性在很大程度上取决于操作系统。

编辑:另外你应该考虑到你的情况,(很可能)你的代码正在被解释! JAva编译为本机代码只有hotspots (并且fromm这里是Hotspot JIT的名称),它们经常被执行。 对于server VM,这是给定代码的10k执行。 你只有1k。

请注意,除了等待一秒钟之外,您的代码正在执行操作。 它正在为for循环输入代码,设置变量以跟踪它并进行迭代。 但更重要的是,您必须了解您的系统还发生了什么。

您的操作系统有一个称为调度程序的东西,它决定在任何给定时间运行的程序(“进程”)访问CPU。 如果某个程序(例如你的程序)进入hibernate状态(定义为“至少在x单位时间内不执行任何操作”),则调度程序通常会将其切换为另一个程序(其中有许多正在运行) 。 当它重新切换时是非确定性的。 因此,即使您碰巧在接近一秒标记(可能是)时切换回来,也不可能完全在一秒钟之后。 因此,“改进”这段代码永远无法帮助解决需要精确一秒循环的潜在问题。

另请注意,调度程序可以随时切换程序:程序无需自愿进入睡眠状态。 这是调度程序的任务; 仲裁哪些进程可以在任何特定点访问系统资源。 因此,时间分析,特别是在这种半实现方式中,并不是特别有用。 使用IDE探查器可以获得更好的想法,因为它们可以测量墙上时间等内容。

也许您真正需要研究的是http://en.wikipedia.org/wiki/Real_time_Java – 如果您需要保证低延迟,您需要一个JVM 一个经过调整的操作系统来为您提供。

据我所知,这里的一个因素是内核系统的滴答时间(我认为台式机为200 tps,服务器为100,RT系统为1000)。 这会导致小的延迟,累积达到55毫秒。 此外, sleep调用将有一些系统开销,这很难自行减少。

System.currentTimeMillis不应用作经过时间的度量。 您应该使用System.nanoTime 。 在这里寻找更多解释。

好吧,你显然可以分解出TimeUnit转换并节省几个周期。 你也可以倒计时而不是倒计时; 使用!= 0测试通常比与其他值比较快。

在进行任何测量之前,您还应确保代码完全JIT(可能需要几分钟的运行时间)。

通常,微基准测试在Java中具有误导性,并且在不知道代码对运行时有多大贡献的情况下进行微观优化往往会浪费精力。 不要为这种运动而烦恼。 编写尽可能最好的代码,在分类实际数据上给它大量的预热时间,然后使用分析器查看它花费时间的位置(也在实际数据上)。 这将告诉您性能调优在哪些方面实际上是高效的。 然后考虑算法改进,这往往会产生最大的好处。 再次使用新代码进行配置文件,看看现在的热门内容。 重复。

请记住,占运行时间1%的东西的无限改进需要付出无限的努力,但只能提高1%。 把你的努力放在有所作为的地方。 而且,特别是在热点Javas中,代码在执行期间继续进行优化,但优化不是完全确定的,不要相信一次执行就能给出真正的性能数字。

你为什么不简单地把它单独睡一觉?

 Thread.sleep(1000); 

我真的想做1000个睡眠命令我推荐这个:

 public static void main(String[] args) throws InterruptedException { // This line is for timing reasons only! long start = System.currentTimeMillis(); final long startTime = System.currentTimeMillis(); long waitTime; for (int i = 0; i < 1000; i++ ) { // Get the time you want to end with. Then substact your current system time! waitTime = (startTime + i + 1)- System.currentTimeMillis(); // Only wait if it would wait (If waitTime is greater than 0. // Everything below 0 will also throw a execption! if(waitTime > 0) Thread.sleep(waitTime); } // Same for those... long duration = System.currentTimeMillis() - start; System.out.println("Loop duration " + duration + " ms."); } 

这将确保您只等到目前有意义!

不幸的是,我的问题被误解了。

实时java被废弃,因此使用Realtime java的建议无效。

经过一些研究,这个测试在一些Windows机器上有最好的结果。

在测试的Windows 8.1上,此测试打印正好1000毫秒。

其他结果:

  • Mac OS X 10.9.1 with Java 1.7.0_25:1180 – 1190ms
  • Ubuntu 12.04 / Corei3 / 4GB:1122 ms

参考

  • 在Windows 7中,Timer的粒度似乎是可变的
  • Hotspot VM内部:时钟,定时器和调度事件 – 第一部分 – Windows
  • 第二部分:系统时间的调整