【问题标题】:Accurate spending time solution精准消费时间解决方案
【发布时间】:2014-02-25 07:42:35
【问题描述】:

考虑如下代码sn-ps

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

////

long long t=0L;
void* time(void* a){//pthread thread start
sleep(1);t++;//show the time
}

我在一些教程中读到,在 Java 中 Thread.sleep(1000) 不完全是 1 秒,如果当时系统很忙,可能会更多,然后操作系统切换到线程较晚。

问题:
这种情况到底是真的还是假的?
对于本机 (C/C++) 代码,这种情况是否相同?
在应用程序中计算秒数的准确方法是什么?

【问题讨论】:

标签: java c++ c multithreading pthreads


【解决方案1】:

其他人已经回答了计时的准确性。不幸的是,没有保证睡眠 X 时间,并在 X.00000 秒(或毫秒、纳秒等)唤醒的方法。

要以秒为单位显示时间,您可以将等待的时间缩短到半秒。然后你不会时不时地跳两秒,因为半秒不会延长到超过一秒(除非你正在运行的操作系统和系统绝对超载并且没有任何东西可以运行什么时候应该——在这种情况下,你应该解决这个问题[获得更快的处理器、更多的内存或任何需要的东西],而不是摆弄你的应用程序的时间)。这适用于“相对较长的时间”,例如一秒或 1/10 秒。对于更高的精度,它不会真正起作用,因为我们现在正在进入“调度抖动”区域。

如果您想要非常准确的计时,那么您可能需要使用实时操作系统,或者至少需要使用“启用实时扩展”的操作系统,这将使操作系统对时间更加严格(在程序员的“易用性”成本,以及操作系统在处理进程方面的效率可能较低,因为与更“懒惰”的计时方法相比,它“切换的频率超过了它需要的频率”)。

还要注意,“可能需要更长时间”,在空闲系统中主要是“定时器的四舍五入”(如果系统滴答每 10 毫秒或 1 毫秒发生一次,则定时器设置为 1000 毫秒 +当前计时器滴答,例如,可能是 1009.999 毫秒或 1000.75 毫秒)。来自调度和一般操作系统开销的其他开销应该在微秒范围内,如果不是任何现代系统上的纳秒 - 毕竟,操作系统可以在一微秒内完成大量工作 - 现代 x86 CPU 将执行 3 个周期每个时钟,时钟运行在 0.3ns 左右。那是每纳秒 10 条指令[当然,缓存未命中等会大大恶化这种情况]。如果操作系统有超过几千条指令从一个进程到另一个进程(对于线程来说更少),那么就有很大的问题。几千条指令@每纳秒 10 条指令 = 几百纳秒。绝对小于一微秒。将其与上次计时器计时后启动计时器的 1 毫秒或 10 毫秒“抖动”进行比较。

当然,如果 CPU 忙于运行其他任务,情况就不同了——那么其他进程上的“剩余运行时间”也会影响唤醒进程所用的时间。

当然,在一个负载很重的内存系统中,“刚刚唤醒”的进程可能还没有“准备好运行”,例如,它可能被换出到磁盘。在这种情况下,需要数十甚至数百毫秒才能将其从磁盘加载回来。

【讨论】:

  • 完美,谢谢Don Petersson,是的,我曾经使用system_current_time,但我想知道另一个更简单的解决方案。真的谢谢。
【解决方案2】:

回答前两个问题:是的,这是真的,是的。

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

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

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

【讨论】:

    【解决方案3】:

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

    准确的方法是什么

    不存在真正准确的方法。
    除非您有一些非常昂贵的带有原子钟的特殊计算机。
    (也没有通常的操作系统。即便如此,我们也可以争论“准确”是什么意思)

    如果可以接受忙等待(高 CPU 负载),请查看 nanoTime 或原生 usleep、HighPerformanceCounter 或适用于您系统的任何内容

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        睡眠功能不准确,但如果是为了显示总秒数,那么你应该在开始时存储当前时间,然后不时显示时差。

        【讨论】:

          【解决方案6】:

          这是真的。任何语言的每个sleep 实现(C 也是)将无法等待 1 秒。它必须处理您的操作系统调度程序,睡眠持续时间只是一个提示:准确地说是the minimum sleep duration,但实际差异取决于无数因素。

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

          问题是无论睡眠持续时间如何,数量级都是相同的。如果你想要一些“准确”的东西,你可以划分你的时间申请并等待更长的时间。例如,当您进行基准测试时,您会更喜欢这种类型的实现,因为增量时间会增加,从而降低不确定性:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-08-08
            • 1970-01-01
            • 2012-02-22
            • 2015-12-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多