可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I don't want to change this code, I'm only interested in JVM, OS or kernel customization/configuration for best results!
I have one second loop (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.");
}
On my Fedora 20 with kernel 3.12 this loop needs 1055 ms.
This is pretty good result, average is more than 1100ms.
Is possible to make this code faster with custom JVM flags or OS configuration?
Loop duration 1055 ms.
回答1:
Calling sleep()
you are basically telling the OS to suspend your thread for AT LEAST X milliseconds. There is no guarantee whatsoever that it will continue executing exactly after this time or the OS will re-scheadule your thread later. Furthermore, the minimum amount of sleep
time and its accuracy heavily depends on the OS.
EDIT: Also you should take into account that in your case , (most probably) your code is being interpreted! JAva compiles to native code only hotspots
(and fromm here comes the name of the Hotspot JIT) which are being executed frequently. For server
VM, this is 10k executions of a given code. You only have 1k.
回答2:
Note that your code is doing things besides waiting for precisely one second. It's entering code for a for loop, setting up variables to track it and iterating. But more than all this, you have to understand what else is happening with your system.
Your operating system has something called a scheduler that decides what running program ('process') gets to access the CPU at any given time. If a program, such as yours, goes to sleep (which is defined as 'don't do anything for at least x unit of time'), the scheduler will often switch it out for another program (of which you have many running). When it gets switched back in is non-deterministic. Thus, even if you happen to be switched back in close to the one second mark (which is likely) it is unlikely that that it will be exactly at one second. Thus, 'improving' this code will never help with the underlying issue of wanting an exactly-one-second loop.
Note, too, that a program can be switched out by the scheduler at any time: the program needn't voluntarily go to sleep. That is the task of the scheduler; to arbitrate which processes gets access to system resources at any particular point. Thus, time-profiling, especially in this sort half-implemented way, is not particularly useful. Use an IDE profiler to get a better idea, because they measure things such as wall time.
回答3:
Maybe what you really need to look into is http://en.wikipedia.org/wiki/Real_time_Java - if you need guarantees of low-latency, you need a JVM and an OS tuned to give you that.
回答4:
By my knowledge, one of the factors here is the kernel system tick time (I think it's 200 tps for desktops, 100 for servers, and 1000 forRT systems). This causes small delays which accumulate up to the 55 ms. Additionally, the sleep
call will have some system overhead, which is hard to reduce by itself.
回答5:
System.currentTimeMillis
should not be used as a measure of elapsed time. You should be using System.nanoTime
. Look here for a bit more explanation.
回答6:
Well, you could obviously factor out the TimeUnit conversion and save a few cycles. You could also count down rather than up; using a !=0 test is usually faster than comparing to other values.
You should also make sure the code is fully JITted (which can take several minutes of running it) before you take ANY measurements.
Generally, microbenchmarks are misleading in Java, and microoptimizing without knowing how much that code contributes to your runtime tends to be wasted effort in any case. Don't bother with this sort of exercise. Write the best code you can, give it lots of warm-up time on an assortment real data, then use a profiler to see where it's spending its time (also on real data). That will tell you where performance tuning will actually be productive. Then consider algorithmic improvements, which tend to yield the highest benefit. Profile again with the new code and see what is hot now. Repeat.
Remember, infinite improvement of something that accounts for 1% of runtime takes infinite effort but yields only 1% improvement. Put your effort where it makes a difference. And, especially in hotspot Javas where code continues to be optimized during execution but that optimization is not fully deterministic, don't trust a single execution to give you real performance numbers.
回答7:
Why don't you simply put it into one single sleep?
Thread.sleep(1000);
I you really want to do 1000 sleep commands I recommend this:
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.");
}
This will make sure you only wait if that makes currently sense!
回答8:
Unfortunately, my question was misunderstood.
Realtime java is abandoned, so advice for using Realtime java is not valid.
After some researches this test has best results on some Windows machines.
On tested Windows 8.1 this tests prints exactly 1000ms.
Other results:
- Mac Os X 10.9.1 with Java 1.7.0_25 : 1180 - 1190ms
- Ubuntu 12.04/Corei3/4GB : 1122 ms
References
- Granularity of Timer seems variable in Windows 7
- Inside the Hotspot VM: Clocks, Timers and Scheduling Events - Part I - Windows
- Part II: Adjustment of System Time