我不想更改此代码,我只对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.");
}
在我的Fedora 20上,带有内核3.12此循环需要1055毫秒。
这是很好的结果,平均水平超过 1100ms 。
可以使用自定义JVM标志或OS配置更快地使此代码?
Loop duration 1055 ms.
调用 sleep()
您基本上告诉OS至少以x毫秒为单位。无法保证它在这段时间之后将继续执行,否则OS将稍后重新缩放线程。此外,sleep
时间的最低量及其准确性在很大程度上取决于OS。
编辑:在您的情况下,您还应该考虑到(很可能)您的代码正在解释!Java仅将hotspots
编译到本机代码(以及Fromm的名称是热点JIT的名称),这些名称是经常执行的。对于server
VM,这是给定代码的10K执行。您只有1k。
请注意,除了精确等待一秒钟之外,您的代码正在做事情。它正在输入用于循环的代码,设置变量以跟踪并迭代。但除此之外,您还必须了解系统正在发生的事情。
您的操作系统具有称为调度程序的内容,该调度程序可以决定在任何给定时间访问CPU的运行程序('Process')。如果一个程序(例如您的程序)进入睡眠状态(定义为"至少在X时间单位单位"),调度程序通常会将其切换为另一个程序(其中许多程序运行)。当它重新回到时,是非确定性的。因此,即使您碰巧被靠近一个第二个标记(这很可能),它也不太可能完全在一秒钟内。因此,"改进"此代码将永远不会有助于解决一个恰好的循环的根本问题。
也要注意,调度程序可以随时切换程序:该程序无需自愿入睡。那是调度程序的任务;仲裁哪些过程可以在任何特定点访问系统资源。因此,时间进行审议,尤其是以这种成就的方式,并不是特别有用。使用IDE Profiler来获得更好的想法,因为它们测量了诸如Wall Time之类的内容。
也许您真正需要研究的是http://en.wikipedia.org/wiki/real_time_java-如果您需要保证低延迟性,则需要一个JVM 和 一个操作系统来给您。
据我所知,这里的因素之一是内核系统滴答时间(我认为台式机是200 TPS,服务器100 tps,1000 forrt Systems)。这会导致较小的延迟,该延迟会累积到55毫秒。此外,sleep
调用将具有一些系统开销,这本身很难减少。
System.currentTimeMillis
不应用作经过时间的度量。您应该使用System.nanoTime
。在这里查找更多的解释。
好吧,您显然可以考虑到时态转换并节省一些周期。您也可以倒数而不是上升;使用A!= 0测试通常比与其他值相比要快。
您还应确保代码已完全夹紧(可能需要几分钟的运行时间),然后进行测量。
一般而言,Microbenchs在Java中具有误导性,并且在不知道该代码对您的运行时有多大贡献的情况下进行微观临时,无论如何在任何情况下都会浪费努力。不要打扰这种锻炼。编写您可以的最佳代码,在分类真实数据上给它大量的热身时间,然后使用profiler查看其在哪里花费时间(也可以在真实数据上)。这会告诉您性能调整实际上会有生产力。然后考虑算法改进,这些算法往往会带来最高的好处。再次使用新代码进行配置,看看现在有什么热点。重复。
请记住,占运行时1%的事物的无限改善需要无限的努力,但提高了1%。将您的努力放在有所作为的地方。而且,尤其是在执行过程中代码继续优化的Hotspot 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被放弃了,因此使用实时Java的建议无效。
在进行一些研究之后,该测试在某些Windows机器上具有最佳效果。
在经过测试的Windows 8.1上测试正好打印1000ms。
其他结果:
- Mac OS X 10.9.1与Java 1.7.0_25:1180-1190ms
- Ubuntu 12.04/corei3/4GB:1122 MS
参考
-
定时器的粒度在Windows 7中似乎可变
-
在热点VM中:时钟,计时器和调度事件 - 第一部分 - Windows
-
第二部分:调整系统时间