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

C# 线程睡眠(TimeSpan)的准确度如何?,c#,multithreading,sleep,stopwatch,C#,Multithreading,Sleep,Stopwatch,我遇到了一个间歇性失败的单元测试,因为所经过的时间不是我所期望的 此测试的示例如下: 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(st

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

此测试的示例如下:

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);
秒表秒表=新秒表();
秒表。开始();
TimeSpan 1秒=新的TimeSpan(0,0,1);

对于(int i=0;iThread.Sleep不用于精确唤醒。实际上,windows体系结构本身不适用于这种情况。

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


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

在一个我想睡眠至少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();
}
公共无效睡眠(整数毫秒)
{
秒表秒表=新秒表();
秒表。开始();
while(stopwatch.elapsedmillesons<毫秒)
{
int timeout=毫秒-stopwatch.elapsedmillisons;
睡眠(超时>=0?超时:0);
}
秒表;
}

对于线程的精确性,睡眠是一个不精确的问题。我认为分辨率大约在10毫秒左右。除了“大约”这么长之外,它不能保证做很多事情。

线程睡眠和计时/节流是非常不同的事情,应该得到适当的处理。睡眠线程是一项一般性任务,allo控制系统,让其他线程和进程有机会执行,而无需具体说明。另一方面,需要精确计时的应用程序节流或调度任务应使用显式计时器执行


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

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

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

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


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

也许你不应该依赖时间偏差来判断你是否成功。最好计算一下你的尝试次数,并根据这一点进行评估:

int tries;

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

Assert.GreaterOrEqual(tries, 3);
int尝试;

对于(trys=0;triesj)来说,出于好奇,为什么有一个单元测试以这种方式测试Thread.Sleep()?我猜您实际上是在测试其他活动是否在3秒内完成,但为什么不调用Thread.Sleep(3000)?@MusiGenesis我更新了这个问题,试图澄清一些事情。只是为了提供信息。自从我发现了这个小代码,我就到处使用它:我同意,线程的意图。睡眠是关于线程优先级,而不是与精确的时钟计时有关。在我们的PC中有铯处理时钟之前,不幸的是精确(绝对)的计时将不可用。:P嗯,我希望大多数人不需要原子钟精确计时。:P我认为大多数CPU中的时钟对于大多数应用程序来说都足够精确,超出了原子振动的测量。:DDo关于分辨率,你有什么参考吗?如果肯定是10毫秒,我可以更改2999到2990…由于其他人注意到的事情(例如影响它的处理器负载),没有硬性和快速的解决方案。基本上,这取决于线程何时获得优先权才能开始执行。不过,我在一些地方看到的轶事证据表明,平均执行时间约为10毫秒。我读到的其他答案我现在找不到。但是,如果它只在内核注意到睡眠时间已过时才结束,那它怎么可能呢花费的时间比我预期的要少?3010ms是可以理解和接受的。在我的情况下,它在达到请求的时间之前停止…虽然是1-2秒。该实现可能会在您指定的时间之前几毫秒设置唤醒时间。如果没有设置,它将总是晚一点唤醒。通过更早地设置时间,它有更好的机会获得在附近。@mezoid:我不认为个人电脑的架构有太多的时间准确性。旧的个人电脑每秒钟只“滴答”18.2次,所以时钟和“滴答”计数过去每52毫秒更新一次。我认为现在它肯定快多了,但我仍然不确定它有多准确。那么它通常在几秒钟内就准确了,还是可以在长时间的睡眠时间间隔内停止几分钟?在我的机器上,它的任一侧都在10毫秒内(记不起确切的nr)如果你真的想,你可以提前安排并旋转cpu,直到达到你的目标。这会是什么测试?for循环工作正常吗?