在c#中睡觉不能正常工作

时间:2014-02-23 12:47:52

标签: c# sleep

以下代码显示sleep(1)平均睡眠时间为2毫秒!

DateTime dt = DateTime.Now;
int i = 0;
long max = -1;
while (true)
{
    Stopwatch st=new Stopwatch();
    st.Restart();
    System.Threading.Thread.Sleep(1);
    long el = st.ElapsedMilliseconds;
    max = Math.Max(el, max);
    i++;

    double time = DateTime.Now.Subtract(dt).TotalMilliseconds;
    if (time >= 1000)
    {
        Console.WriteLine("Time =" + time);
        Console.WriteLine("i =" + i);
        Console.WriteLine("max ="+max);
        System.Threading.Thread.Sleep(200);
        i = 0;
        dt = DateTime.Now;
        max = -1;
    }
}

典型输出:

Time =1000.1553
i =495
max =5
有人可以解释一下这个原因吗?我该如何解决这个问题?!

3 个答案:

答案 0 :(得分:6)

获得2毫秒是相当不寻常的,大多数运行代码的人都会得到15分。它取决于机器,主要取决于您在机器上运行的其他程序。例如,改变它的一种方法是启动Chrome,你会看到(接近)1毫秒的睡眠。

您应该显示更多数字以避免舍入工件。代码的简化:

static void Main(string[] args) {
    Stopwatch st = new Stopwatch();
    while (true) {
        st.Restart();
        System.Threading.Thread.Sleep(1);
        st.Stop();
        Console.Write("{0} ", st.Elapsed.Ticks / 10000.0);
        System.Threading.Thread.Sleep(200);
    }
}

在我的机器上产生:

16.2074 15.6224 15.6291 15.5313 15.6242 15.6176 15.6152 15.6279 15.6194 15.6128
15.6236 15.6236 15.6134 15.6158 15.6085 15.6261 15.6297 15.6128 15.6261 15.6218
15.6176 15.6055 15.6218 15.6224 15.6212 15.6134 15.6128 15.5928 15.6375 15.6279
15.6146 15.6254 15.6248 15.6091 15.6188 15.4679 15.6019 15.6212 15.6164 15.614 
15.7504 15.6085 15.55 15.6248 15.6152 15.6248 15.6242 15.6158 15.6188 15.6206 ...

这是正常的输出,我的机器上没有运行的程序弄乱了操作系统。这将是它在大多数机器上的工作方式。

有关正在发生的事情的一些背景知识。当您使用大于0的值调用Thread.Sleep()时,您自愿放弃处理器并且您的线程进入等待状态。它将在操作系统的线程调度程序运行且足够的时间到期时恢复。

关于该句子的关键是“当线程调度程序运行时”。它在Windows中的不同时间运行,由时钟中断驱动,将处理器从HALT状态唤醒。这从内核开始,时钟中断的一个主要任务是增加时钟值。例如,DateTime.Now和Environment.TickCount

使用的那个

时钟没有无限分辨率,只有在发生时钟中断时才会改变。默认情况下,在所有现代Windows版本中,该时钟中断每秒发生64次。这使得时钟精度为1/64 = 15.625毫秒。您可以在我的机器上的程序输出中清楚地看到此值。

所以在你的机器上发生的事情是程序改变了时钟中断率。这是Windows 3.1的一个相当不幸的继承,Windows 3.1是第一个支持多媒体计时器的Windows版本。定时器可以高速打勾以支持需要使用媒体进行操作的程序,例如设置GIF文件的动画,调整视频播放器的帧速率,保持声卡充满声音而不会出现口吃或过度延迟。像Chrome这样的程序。

他们通过致电timeBeginPeriod()来做到这一点。它们通常是全猪并且选择最小的允许值,1毫秒。你的机器显然是2毫秒。你也可以这样做,你会看到Sleep(1)呼叫现在大约需要1毫秒而不是2分钟。当你不再需要高速率时,不要忘记调用timeEndPeriod()。

但请记住,这是非常不友好的事情。唤醒处理器往往对电池寿命非常不利,这一直是便携式机器的问题。这解释了这个网站的创始人在他的博客"Why does Windows have terrible battery life"中迷惑了什么。它没有,Chrome的电池寿命很长:​​)如果你想找出什么程序与时钟混乱,那么你可以从命令行运行powercfg -energy

答案 1 :(得分:5)

我认为看到这个结果并不奇怪。秒表本身可能需要一毫秒。我非常怀疑你可以期待精确的1毫秒。总是涉及到开销,我怀疑睡眠可以保证睡眠时间是精确的。

我个人希望的范围是1-5毫秒。

答案 2 :(得分:3)

Thread.Sleep旨在暂停的线程至少您指定的毫秒数。它基本上离开了当前thead的执行,并且由操作系统的调度程序再次唤醒它。问题是,您无法确定底层操作系统的调度程序是否允许线程立即恢复。

我认为,System.Threading.Thread.SpinWait就是你要找的。