C# 线程的精度是否仍然很差?

C# 线程的精度是否仍然很差?,c#,windows,thread-sleep,windows-server-2016,C#,Windows,Thread Sleep,Windows Server 2016,我的印象是Thread.Sleep(x)并不精确,它所能做的就是让线程至少睡眠xms。请参阅,和 当睡眠时间非常短(例如1ms)时,您可能会发现线程偶尔睡眠约15ms。这是由于时钟中断率,默认情况下为每秒64次 几年前我尝试过这个,事实上,我也体验过15ms分辨率。然而,我刚刚又尝试了一次,现在我看到1ms到2ms分辨率很少>2ms 发生了什么变化?.NET是否发生了变化(我现在使用的是4.6,不记得两年前我用过什么了)?也许是操作系统改变了?(我使用过AWS EC2 Windows Serve

我的印象是
Thread.Sleep(x)
并不精确,它所能做的就是让线程至少睡眠
x
ms。请参阅,和

当睡眠时间非常短(例如
1ms
)时,您可能会发现线程偶尔睡眠约
15ms
。这是由于时钟中断率,默认情况下为每秒64次

几年前我尝试过这个,事实上,我也体验过
15ms
分辨率。然而,我刚刚又尝试了一次,现在我看到
1ms
2ms
分辨率很少>2ms

发生了什么变化?.NET是否发生了变化(我现在使用的是
4.6
,不记得两年前我用过什么了)?也许是操作系统改变了?(我使用过AWS EC2 Windows Server,现在仍在使用,但可能已经有了更新。)

我的简单测试程序:

private static Stopwatch sw =new Stopwatch();
static void Main(string[] args)
{
    var timer = new Stopwatch();
    var results = new List<long>();
    for (int i = 0; i < 100000; i++)
    {
        timer.Restart();
        Thread.Sleep(1);
        results.Add(timer.ElapsedMilliseconds);
    }

    foreach (var item in results.Where(x => x > 1).ToList())
    {
        Console.WriteLine(item );
    }

    Console.ReadLine();

}
private static Stopwatch sw=新秒表();
静态void Main(字符串[]参数)
{
var timer=新秒表();
var results=新列表();
对于(int i=0;i<100000;i++)
{
timer.Restart();
睡眠(1);
结果。添加(计时器。延时毫秒);
}
foreach(results.Where(x=>x>1.ToList()中的变量项)
{
控制台写入线(项目);
}
Console.ReadLine();
}

线程.Sleep
的精度(以及内核32中的底层Windows API
Sleep
函数)取决于系统时钟的分辨率,的默认滴答频率约为15 ms。应用程序可以请求更高的分辨率,在这种情况下,全局使用请求的最高分辨率

在这种情况下,您可能会看到低于15毫秒的分辨率,因为系统上运行的某些东西要求更高的分辨率

如果您的应用程序实际需要低于15毫秒的睡眠时间,它可以通过本机函数请求更高的分辨率


但是,请注意,底层计时器设备可能不支持您请求的分辨率,因此,除非您完全确定代码将在哪个硬件上运行,否则编写依赖于此行为的代码不是一个好做法。

测试时,您的计算机上还有什么其他功能?这可能会影响计时。@Carcigenicate现在什么都不知道-也许这就是为什么我看到了相当高的精确度?我最喜欢的是当我看到人们试图睡眠1微秒时…在这里搜索
timebeginperiod
,如果你不熟悉它对
睡眠
和其他方面的影响。@500 InternalServerError
timebeginperiod
在我链接的帖子中提到过几次。我在问
Thread.Sleep
的精度是否已经改变,因为我现在获得了高精度。我认为@Carcigenicate有一个很好的观点——也许我应该在后台运行CPU密集型任务时进行测试。ntdll.dll中的本机系统调用是
ntquerytimeresolution(PULONG MaximumTime、PULONG MinimumTime、PULONG CurrentTime)
NtSetTimerResolution(ULONG DesiredTime、布尔设置分辨率、PULONG实际时间)
,使用100 ns的时间单位。另外,在winmm.dll函数中,请注意,它是根据实际计时器分辨率更新的,而不是
GetTickCount
,它似乎使用一个硬编码的计数,每15.625 ms更新一次,而不管实际分辨率如何。@CollinDauphinee谢谢。我注意到如果我激发了你们一群人管视频,我开始看到更多的野生测量,其中
Thread.Sleep(x)
x
睡眠时间长约10%。