我有一个关于C#线程的小问题。由于某种原因,当我打开Chrome浏览器时,我的线程从32ms延迟加速到16ms延迟,当我关闭Chrome浏览器时,它又回到32ms。我使用Thread.Sleep(1000 / 60)
来处理延迟。有人能解释一下为什么会发生这种情况,或者建议一个可能的解决方案吗?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication2
{
class Program
{
static bool alive;
static Thread thread;
static DateTime last;
static void Main(string[] args)
{
alive = true;
thread = new Thread(new ThreadStart(Loop));
thread.Start();
Console.ReadKey();
}
static void Loop()
{
last = DateTime.Now;
while (alive)
{
DateTime current = DateTime.Now;
TimeSpan span = current - last;
last = current;
Console.WriteLine("{0}ms", span.Milliseconds);
Thread.Sleep(1000 / 60);
}
}
}
}
5条答案
按热度按时间v9tzhpje1#
只是一个帖子来确认马修的正确答案。线程的准确性。睡眠()受Windows上的时钟中断率影响。默认情况下,每秒滴答64次,每15.625毫秒一次。()只有在这样的中断发生时才能完成,这里的心理意象是由“睡眠”这个词诱发的,处理器实际上是休眠的,不执行代码。只有那个时钟中断才会再次唤醒它,继续执行你的代码。
你选择的1000/60是一个非常不满意的选择,它要求16毫秒,略高于15.625,所以你总是在至少2个滴答之后醒来:2 x 15.625 = 31毫秒。您测量的值。
然而,中断率不是固定的,它可以由程序更改。它通过调用CreateTimerQueueTimer()或遗留timeBeginPeriod()来实现。浏览器通常需要这样做。一些简单的事情,如动画GIF需要一个更好的计时器,因为GIF帧时间是以10毫秒为单位指定的。或者通常任何与多媒体相关的操作都需要它。
一个程序这样做的一个非常丑陋的副作用是,时钟中断率的增加会对整个系统产生影响。就像你的程序一样。你的计时器突然变得准确,你实际上得到了你要求的睡眠时间,16毫秒。所以Chrome将频率改为每秒1000次。这是支持的最大值。如果你有一个竞争对手的操作系统,则是good for business。
你可以通过选择一个更接近默认中断率的睡眠时间来避免这个问题。如果你要求15,你会得到15.625,Chrome对此没有影响。31是下一个最佳点。等等,15.625的整数倍和向下舍入。
更新:请注意,这种行为改变了just recently。从Win10版本2004开始,这种影响不再是全局的,所以Chrome不再影响你的程序。从Win 11开始,一个有非活动窗口的应用程序将以默认的中断率运行。
bqujaahr2#
发生这种情况的原因可能是Chrome(或Chrome的某些组件)调用
timeBeginPeriod()
时使用的值增加了Windows API函数Sleep()
(从Thread.Sleep()
调用)的分辨率。更多信息请参见此主题:Can I improve the resolution of Thread.Sleep?
几年前,我注意到Windows Media Player的这种行为:我们的一个应用程序的行为根据Windows Media Player是否运行而改变,结果是WMP调用了
timeBeginPeriod()
。然而,一般来说,
Thread.Sleep()
(以及Windows APISleep()
)是非常不准确的。5ktev3wc3#
基本上,
Thread.Sleep
isn't very accurate。Thread.Sleep(1000/60)
(计算结果为Thread.Sleep(16)
),要求线程进入睡眠状态,并在经过16毫秒后返回。但是,该线程可能要等到经过更长的时间后才能再次执行;例如32 ms。至于为什么Chrome会产生影响,我不知道,但由于Chrome为每个标签生成一个新线程,它将对系统的线程行为产生影响。
mzmfm0qo4#
首先,1000 / 60 = 16毫秒
PC时钟的分辨率约为18- 20 ms,
Sleep()
,DateTime.Now
的结果将四舍五入为该值的倍数。因此,
Thread.Sleep(5)
和Thread.Sleep(15)
将延迟相同的时间,可以是20、40甚至60 ms。您无法得到太多保证,Sleep()
的参数只是最小值。另一个占用CPU(哪怕是一点点)的进程(Chrome)也会影响程序的行为。这和你看到的正好相反,所以这里发生了一些其他的事情。尽管如此,这是关于舍入到时间片的。
t3irkdon5#
你遇到了
DateTime
的分辨率问题。你应该使用Stopwatch
来实现这种精度。Eric Lippert statesDateTime
只精确到30毫秒左右,所以在这种情况下你用它读的数据不会告诉你任何东西。测量是问题的一半。循环的实际时间变化是由于
Sleep
分辨率(如其他答案所述)。