代码之家  ›  专栏  ›  技术社区  ›  mezoid

线程睡眠(TimeSpan)的准确度如何?

  •  16
  • mezoid  · 技术社区  · 16 年前

    此测试的示例如下:

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    
    TimeSpan oneSecond = new TimeSpan(0, 0, 1);
    
    for(int i=0; i<3; i++)
    {
        Thread.Sleep(oneSecond);
    }
    
    stopwatch.Stop();
    
    Assert.GreaterOrEqual(stopwatch.ElapsedMilliseconds, 2999);
    

    预期值:大于或等于2999 但是是:2998

    我不明白怎么可能少于3秒。线程、睡眠或秒表是否存在我不知道的准确性问题?

    作为对下面一些问题的更新。正在进行单元测试的场景是一个类,它允许用户调用一个方法来执行某些操作,如果失败,请等待一秒钟并调用该方法。上面显示的测试只是正在发生的情况的近似值。

    假设我想调用一个方法DoSomething()…但是如果DoSomething()引发异常,我希望能够重试调用它最多3次,但每次尝试之间要等待1秒。在本例中,单元测试的目的是验证当我们请求3次重试,每次重试之间等待1秒时,所用的总时间是否大于3秒。

    6 回复  |  直到 16 年前
        1
  •  19
  •   Havenard    16 年前

    您的线程正在与其他线程共享CPU时间。再次轮到您时,睡眠将立即结束,内核会注意到睡眠时间已过,因此这并不准确。

    CPU负载、进程优先级、并发线程数,甚至来自其他进程,都会对其产生影响。

        2
  •  7
  •   Spencer Ruport    16 年前

    睡眠不用于精确唤醒。事实上,windows体系结构本身并不适用于这种情况。

        3
  •  3
  •   Mark Gearing    15 年前

    在快速的实验中,我注意到一个代码片段,如。。。

    执行{Debug.WriteLine(DateTime.Now.TimeOfDay.totalmillizes.ToString();}while(1);

    看起来Windows计时器的粒度为1/64秒。如果你需要比这更好的东西,那么我会感觉到你的痛苦,但这是你必须适应的框架。(Windows不是硬实时操作系统,也不自称是)。

        4
  •  2
  •   jrista    16 年前

    请记住,如果您需要时间精确的进程或同步,那么使用windows中的正常进程很难实现这一点。您需要利用windows实时优先级来成功地实现精确的计时或节流,因为如果任何线程被另一个线程抢占,windows可以在任何时候休眠任何线程。

        5
  •  1
  •   Matthew Scharley    16 年前

    在一个我想睡眠至少x毫秒的应用程序中,我使用了一些类似以下的代码:

    public void Sleep(int milliseconds)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
    
        while (stopwatch.ElapsedMilliseconds < milliseconds)
        {
            int timeout = milliseconds - stopwatch.ElapsedMilliseconds;
            Thread.Sleep(timeout >= 0 ? timeout : 0);
        }
    
        stopwatch.Stop();
    }
    

    根据线程的精确程度,睡眠是不精确的。我认为分辨率大约在10毫秒左右。除了“大约”这么长的时间,它不能保证做很多事情。

        6
  •  -1
  •   Oliver    15 年前

    int tries;
    
    for(tries=0; tries<3; tries++)
    {
        Thread.Sleep(oneSecond);
    }
    
    Assert.GreaterOrEqual(tries, 3);