我可以提高 Thread.Sleep 的分辨率吗?

发布于 2024-12-07 14:25:45 字数 1734 浏览 1 评论 0原文

Thread.Sleep() 分辨率从 1 到 15.6ms 不等

给定这个控制台应用程序:

class Program
{
    static void Main()
    {
        int outer = 100;
        int inner = 100;
        Stopwatch sw = new Stopwatch();

        for (int j = 0; j < outer; j++)
        {
            int i;
            sw.Restart();
            for (i = 0; i < inner; i++)
                Thread.Sleep(1);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
}

我预计输出是 100 个接近 100 的数字。相反,我得到的是这样的结果:

99 99 99 100 99 99 99 106 106 99 99 99 100 100 99 99 99 99 101 99 99 99 99 99 101 99 99 99 99 101 99 99 99 100 99 99 99 99 99 103 99 99 99 99 100 99 99 99 99 813 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 第1559章 1560 第1559章 第1559章 第1559章 第1559章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1558章 第1559章 第1558章 第1558章 第1558章 第1558章 第1558章

但有时我得不到准确的结果;每次都会~1559。

为什么不一致?

一些谷歌搜索告诉我,15.6ms 是一个时间片的长度,所以这解释了 ~1559 结果。但为什么我有时会得到正确的结果,而有时却只是得到 15.6 的倍数呢? (例如 Thread.Sleep(20) 通常会给出〜31.2ms)

它如何受到硬件或软件的影响?

我问这个是因为是什么让我发现了它:

我一直在开发我的应用程序32位双核机器。今天我的机器升级到 64 位四核,并重新安装了完整的操作系统。 (这两种情况都是 Windows 7 和 .NET 4,但是我不能确定旧机器有 W7 SP1;新机器有。)

在新机器上运行我的应用程序时,我立即注意到我的表单需要更长的时间才能淡出。我有一个自定义方法来淡入淡出我的表单,它使用 Thread.Sleep() ,其值从 10 到 50 不等。在旧系统上,这似乎每次都很完美。在新系统上,褪色所需的时间比应有的要长得多。

为什么我的旧系统和新系统之间的行为会发生变化?这与硬件或软件有关吗?

我可以使其始终准确吗? (~1ms 分辨率)

我可以在程序中做些什么来使 Thread.Sleep() 可靠地精确到 1ms 左右吗?甚至10ms?

Thread.Sleep() resolution varies from 1 to 15.6ms

Given this console app:

class Program
{
    static void Main()
    {
        int outer = 100;
        int inner = 100;
        Stopwatch sw = new Stopwatch();

        for (int j = 0; j < outer; j++)
        {
            int i;
            sw.Restart();
            for (i = 0; i < inner; i++)
                Thread.Sleep(1);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
}

I expected the output to be 100 numbers close to 100. Instead, I get something like this:

99
99
99
100
99
99
99
106
106
99
99
99
100
100
99
99
99
99
101
99
99
99
99
99
101
99
99
99
99
101
99
99
99
100
99
99
99
99
99
103
99
99
99
99
100
99
99
99
99
813
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1559
1560
1559
1559
1559
1559
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1558
1559
1558
1558
1558
1558
1558

But sometimes I won't get any accurate results; it will be ~1559 every time.

Why isn't it consistent?

Some googling taught me that 15.6ms is the length of a timeslice, so that explains the ~1559 results. But why is it that I sometimes get the right result, and other times I just get a multiple of 15.6? (e.g. Thread.Sleep(20) will usually give ~31.2ms)

How is it affected by hardware or software?

I ask this because of what led me to discover it:

I had been developing my application on a 32 bit dual-core machine. Today my machine was upgraded to 64bit quad-core with a complete OS re-install. (Windows 7 and .NET 4 in both cases, however I can't be sure the older machine had W7 SP1; the new one does.)

Upon running my application on the new machine, I immediatey notice my forms take longer to fade out. I have a custom method to fade my forms which uses Thread.Sleep() with values varying from 10 to 50. On the old system this seemed to work perfectly every time. On the new system it's taking much longer to fade than it should.

Why did this bahavior change between my old system and my new system? Is this related to hardware, or software?

Can I make it consistently accurate? (~1ms resolution)

Is there something I can do in my program to make Thread.Sleep() reliably accurate to about 1ms? Or even 10ms?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

命比纸薄 2024-12-14 14:25:45

“Sleep 函数将当前线程的执行暂停至少指定的时间间隔。”

-> http://social.msdn.microsoft.com/Forums/en/clr/thread/facc2b57-9a27-4049-bb32-ef093fbf4c29

“The Sleep function suspends the execution of the current thread for at least the specified interval.”

-> http://social.msdn.microsoft.com/Forums/en/clr/thread/facc2b57-9a27-4049-bb32-ef093fbf4c29

ˇ宁静的妩媚 2024-12-14 14:25:45

答案是不使用 Thread.Sleep 而是使用高分辨率计时器。您需要在繁忙的循环中进行淡入淡出,但这听起来似乎没有问题。您根本无法期望 Thread.Sleep 具有高分辨率,而且它因在不同硬件上的行为不同而臭名昭著。

您可以使用秒表 .net 上的类,如果硬件支持高分辨率性能计数器,则使用它们。

The answer is not to use Thread.Sleep and instead use a high resolution timer. You'll need to do your fade in a busy loop, but it sounds like that would be no problem. You simply cannot expect high resolution from Thread.Sleep and it is notorious for behaving differently on different hardware.

You can use the Stopwatch class on .net which uses high-resolution performance counters if they are supported on the hardware.

半岛未凉 2024-12-14 14:25:45

我可以回答我的一个问题:我可以使其始终准确吗? (~1ms 分辨率)

是的,我似乎可以,使用 timeBeginPeriod() 和 timeEndPeriod()。

我已经测试过这个并且它有效。

我读过的一些内容表明,在应用程序的持续时间内调用 timeBeginPeriod(1) 是一个坏主意。但是,在短方法开始时调用它,然后在方法结束时使用 timeEndPeriod() 清除它应该没问题。

尽管如此,我也会研究如何使用计时器。

I can answer one of my questions: Can I make it consistently accurate? (~1ms resolution)

Yes, it seems that I can, using timeBeginPeriod() and timeEndPeriod().

I've tested this and it works.

Some things I've read suggest that calling timeBeginPeriod(1) for the duration of the application is a bad idea. However, calling it at the start of a short method and then clearing it with timeEndPeriod() at the end of the method should be okay.

Nevertheless I will also investigate using timers.

谁的新欢旧爱 2024-12-14 14:25:45

您的计算机上正在运行一个程序,该程序正在调用 timeBeginPeriod() 和 timeEndPeriod()。通常,媒体相关程序使用 timeSetEvent() 设置一毫秒计时器。它也会影响 Sleep() 的分辨率。

您可以自己调用这些函数以获得一致的行为。不过对于 UI 效果来说并不是很合理。这对笔记本电脑的电池寿命相当不友好。

休眠 20 毫秒并实际获得 2/64 秒是合乎逻辑的,CPU 根本不会足够快地醒来以注意到 20 毫秒已经过去。您只能得到 1/64 秒的倍数。因此,实现淡入淡出效果的计时器的合理选择是 15 毫秒,在最坏情况下为您提供 64 fps 动画。假设你的效果绘制得足够快。如果 timeBeginPeriod 被调用,你会有点偏离,但不会偏离太多。从时钟计算动画阶段也有效,但在我的书中有点矫枉过正。

You have a program running on your machine that is calling timeBeginPeriod() and timeEndPeriod(). Typically a media related program that uses timeSetEvent() to set a one millisecond timer. It affects the resolution of Sleep() as well.

You could pinvoke these functions yourself to get consistent behavior. Not terribly reasonable for UI effects though. It is rather unfriendly to battery life on a laptop.

Sleeping for 20 msec and actually getting 2/64 seconds is otherwise logical, the cpu simply won't wake up soon enough to notice that 20 msec have passed. You only get multiples of 1/64 seconds. So a reasonable choice for a Timer that implements fading effects is 15 msec, giving you 64 fps animation worst case. Assuming that your effect draws fast enough. You'll be a bit off if timeBeginPeriod was called but not by much. Calculating the animation stage from the clock works too but is a bit overkill in my book.

泪冰清 2024-12-14 14:25:45

你的做法是错误的。你永远不会得到准确的睡眠,而且你的机器越忙,你的睡眠循环就会变得越错误。

您应该做的是查看已经过去了多少时间并相应地进行调整。尽管绕着 Sleep 转是一个坏主意,但“更好”的实现方式会复杂得多。我将保持我建议的解决方案简单。

  • 调用 DateTime.Now.Ticks 并将其保存在变量 (startTick) 中。
  • 在循环中,像您已经在做的那样调用 Sleep 。
  • 再次调用 DateTime.Now.Ticks 并从中减去 startTick - 该值将是自开始淡入淡出 (timeSinceStart) 以来已经过去的 100 纳秒时间单位。
  • 使用 timeSinceStart 计算经过这么多时间后应该褪色多少。
  • 重复直到它完全褪色。

Your approach is wrong. You will never get sleep to be accurate, and the more busy your machine is, the more wrong your sleep loop will become.

What you should be doing is looking at how much time has passed and adapting accordingly. Although spinning around Sleep is a bad idea, "better" ways of doing it will be significantly more complex. I'll keep my suggested solution simple.

  • Call DateTime.Now.Ticks and save it in a variable (startTick).
  • In your loop, call Sleep as you are already doing.
  • Call DateTime.Now.Ticks again and subtract startTick from it - this value will be how many 100 nanosecond units of time have passed since you started the fade (timeSinceStart).
  • Using timeSinceStart calculate how much you should be faded with that much time elapsed.
  • Repeat until you have completely faded it.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文