Java 精确的花费时间解

Java 精确的花费时间解,java,c++,c,multithreading,pthreads,Java,C++,C,Multithreading,Pthreads,考虑以下代码片段 class time implement Runnable{ long t=0L; public void run(){ try{while(true){Thread.sleep(1000);t++;/*show the time*/}}catch(Throwable t){} } } //// 我在一些教程中读到,Java Thread.sleep1000并不完全是1秒,如果系统当时很忙,那么操作系统切换到线程的时间可能会更长。 问题: 这个案子到底是真的还是假的

考虑以下代码片段

class time implement Runnable{
 long t=0L;
 public void run(){
  try{while(true){Thread.sleep(1000);t++;/*show the time*/}}catch(Throwable t){}
 }
}
////

我在一些教程中读到,Java Thread.sleep1000并不完全是1秒,如果系统当时很忙,那么操作系统切换到线程的时间可能会更长。 问题: 这个案子到底是真的还是假的? 本机C/C++代码的情况相同吗?
在应用程序中,准确的秒数计算方法是什么?

是的,确实不准确。 对于C/C++中的简单睡眠函数和几乎所有其他函数都是一样的。 根据您的系统,可能会有更好的功能可访问, 但是:

准确的方法是什么

真正准确的方法并不存在。 除非你有一些非常昂贵的特殊计算机,包括原子钟。 也没有常见的操作系统。即使这样,我们也可以争论准确的含义


如果繁忙等待高CPU负载是可以接受的,请查看nanoTime或本机usleep、HighPerformanceCounter或任何适用于您的系统的工具来回答前两个问题:是的,是的

首先是超时到期和操作系统注意到超时之间的时间,然后是操作系统重新安排进程的时间,最后是从进程被唤醒到轮到它运行的时间。这一切需要多长时间?没办法说

由于这一切都是在操作系统级别上完成的,所以用什么语言编程并不重要


至于更准确的方法呢?没有。您可以使用更高精度的计时器,但无法避免上述延迟。

睡眠调用告诉系统停止线程执行至少一段指定为参数的时间段。当系统有机会恢复线程执行时,它将恢复线程执行,这实际上取决于许多因素,如硬件、线程优先级等。。要或多或少准确地测量时间,您可以在执行开始时存储时间,然后在每次需要时计算时间增量。

睡眠功能不准确,但如果目的是显示总秒数,则应在开始时存储当前时间,然后不时显示时差。

这是正确的。任何C语言中的每个睡眠实现也将无法精确等待1秒。它必须处理您的操作系统调度程序,睡眠持续时间只是一个提示:精确地说,最短睡眠持续时间,但实际差异取决于亿万个因素

如果你想要一个非常高分辨率的时钟,试图找出偏差是很棘手的。在大多数情况下,大约有1~5毫秒

问题是,无论睡眠时间长短,数量级都是相同的。如果你想得到一些准确的信息,你可以将你的时间应用程序分开,等待更长的时间。例如,当您进行基准测试时,您会更喜欢这种类型的实现,因为增量时间会增加,从而减少不确定性:

// get t0
// process n times
// get t1    
// compute average time : (t1-t0)/n

其他人则回答了时间的准确性问题。不幸的是,没有一种方法可以保证睡眠时间为X,而醒来时间恰好为X.00000秒或毫秒、纳秒等

对于以秒为单位显示时间,您可以将等待时间缩短到半秒。这样,您就不会有两秒钟的时间跳变,因为半秒钟不会延长到一秒钟以上,除非您运行的操作系统和系统完全过载,并且在应该运行的时候没有任何东西可以运行-在这种情况下,您应该解决这个问题[获得更快的处理器、更多的内存,或者其他任何需要的东西],不要摆弄你申请的时间。这在相对较长的时间段内运行良好,例如1秒或十分之一秒。为了获得更高的精度,它不会真正起作用,因为我们现在正进入调度抖动区

如果您想要非常精确的计时,那么您可能需要使用实时操作系统,或者至少需要使用启用了实时扩展的操作系统,这将允许操作系统在时间方面更加严格,而程序员则会以易于使用为代价,并且操作系统在处理进程方面的效率可能会更低,因为与更懒惰的计时方法相比,它的切换频率比需要的要高

还要注意的是,在空闲系统中,可能需要更长的时间,主要是计时器的四舍五入。如果系统滴答声每10ms或1ms发生一次,则计时器设置为1000ms+当前计时器滴答声的剩余值,例如,可能是1009.999ms或1000.75ms。另一种开销,来自调度和一般操作系统开销,在任何现代系统上都应该在微秒范围内(如果不是纳秒的话)——毕竟,一个操作系统可以在微秒内完成相当多的工作——现代x86 CPU将每时钟执行3个周期,时钟大约运行0.3秒。这是每纳秒10条指令[当然,缓存未命中,这将使这种戏剧性的情况恶化] 盟友]。如果操作系统有数千条以上的指令从一个进程转到另一个进程,那么线程就更少了,那么就有相当大的问题了。几千条指令@每纳秒10条指令=几百纳秒。绝对不到一微秒。将其与上次计时器勾选后启动计时器的1毫秒或10毫秒抖动进行比较

当然,如果CPU忙于运行其他任务,这是不同的——那么在其他进程上运行的剩余时间也会影响唤醒进程所需的时间


当然,在一个负载沉重的内存系统中,刚刚唤醒的进程可能还没有准备好运行,例如,它可能被交换到磁盘上。在这种情况下,需要数十毫秒(如果不是数百毫秒的话)才能将其从磁盘加载回来

太好了,谢谢Don Peterson,是的,我以前用系统当前时间代替,但我想知道另一个更简单的解决方案。真的谢谢。即使你不睡觉,只需轮询System.nanoTime,你也会在一台安静的机器上看到高达毫秒的抖动。
// get t0
// process n times
// get t1    
// compute average time : (t1-t0)/n