繁体   English   中英

Thread.Sleep(TimeSpan)的准确度如何?

[英]How accurate is Thread.Sleep(TimeSpan)?

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

此测试的示例如下:

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秒。

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

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

Thread.Sleep不适用于精确唤醒。 实际上,Windows体系结构本身并不适用于此类事物。

快速试验,我注意到代码片段像...

do {Debug.WriteLine(DateTime.Now.TimeOfDay.TotalMilliseconds.ToString()); } while(1);

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

看起来Windows计时器的粒度为1/64秒。 如果你需要更好的话,那么我会感受到你的痛苦,但那是你必须适应的框架。 (Windows不是一个硬实时操作系统,并不声称是)。

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

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

在我想睡至少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的精确程度,它根本不准确。 我认为分辨率大约是10ms左右。 除了“近似”这么久之外,我们无法做任何事情。

也许你不应该依赖时间偏见来找出你是否成功。 更好地计算您的尝试次数并对此进行评估:

int tries;

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

Assert.GreaterOrEqual(tries, 3);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM