20

我遇到了一个间歇性失败的单元测试,因为经过的时间不是我所期望的。

此测试的示例如下:

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 秒。Thread.Sleep 或 Stopwatch 是否存在我不知道的准确性问题?

就像对以下一些问题的更新一样。正在单元测试的场景是一个类,它允许调用一个方法来执行某些操作,如果它失败,请稍等片刻并调用该方法。上面显示的测试只是正在发生的事情的一个近似值。

假设我想调用一个方法 DoSomething()...但是如果 DoSomething() 抛出异常,我希望能够重试调用它最多 3 次,但每次尝试之间等待 1 秒。在这种情况下,单元测试的目的是验证当我们请求 3 次重试且每次重试之间等待 1 秒时,所用的总时间是否大于 3 秒。

4

6 回答 6

19

您的线程正在与其他线程共享 CPU 时间。再次轮到您时,睡眠将结束,并且内核注意到睡眠时间已经过去,因此它并不那么准确。

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

于 2009-08-20T02:52:57.293 回答
7

Thread.Sleep 不打算用于精确唤醒。确实,Windows 体系结构本身并不适合这种事情。

于 2009-08-20T02:36:42.687 回答
4

快速试验,我注意到一个代码片段,如......

做 { Debug.WriteLine( DateTime.Now.TimeOfDay.TotalMilliseconds.ToString() ); } 而 ( 1 );

多次显示相同的数字,然后跳转到多次显示的新数字,等等。这些数字集之间的差距始终为 15.625 毫秒,我注意到是 1000 / 64。

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

于 2009-12-15T07:27:40.347 回答
2

线程休眠和定时/节流是非常不同的事情,应该适当对待。休眠线程是一项通用任务,允许系统给其他线程和进程执行的机会,而无需具体说明。另一方面,限制应用程序或调度需要精确计时的任务应该使用显式计时器来执行。

请记住,如果您需要时间准确的流程或同步,您将很难通过 Windows 中的正常流程来实现。您需要利用 Windows 实时优先级来成功实现准确的计时或节流,因为如果任何线程被另一个线程抢占,Windows 可以随时休眠任何线程。

于 2009-08-20T03:06:44.120 回答
1

在一个我想至少休眠 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();
}

针对 Thread.Sleep 的准确程度,它根本不准确。我认为分辨率在 10 毫秒左右。除了“大约”这么长之外,不能保证做很多事情。

于 2009-08-20T02:58:30.437 回答
-1

也许您不应该依靠时间偏差来确定您是否成功。更好地计算您的尝试次数并对此进行评估:

int tries;

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

Assert.GreaterOrEqual(tries, 3);
于 2009-12-15T08:02:30.307 回答