C# 为什么其他应用程序运行时,线程睡眠等待的时间比请求的时间长?
关于C#中的线程,我有一个小问题。 由于某些原因,当我打开Chrome时,我的线程从32毫秒延迟加速到16毫秒延迟,当我关闭Chrome时,它又回到32毫秒。我正在使用C# 为什么其他应用程序运行时,线程睡眠等待的时间比请求的时间长?,c#,.net,multithreading,behavior,C#,.net,Multithreading,Behavior,关于C#中的线程,我有一个小问题。 由于某些原因,当我打开Chrome时,我的线程从32毫秒延迟加速到16毫秒延迟,当我关闭Chrome时,它又回到32毫秒。我正在使用Thread.Sleep(1000/60)作为延迟。 有人能解释为什么会发生这种情况,并提出可能的解决方案吗 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threadi
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);
}
}
}
}
您正在使用
DateTime
解决问题。对于这种精度,您应该使用秒表。该DateTime
仅精确到30毫秒左右,因此在本例中,您的读数不会告诉您任何信息
测量是你问题的一半。循环的实际时间变化是由于
睡眠分辨率(如其他答案所述)。首先,1000/60=16毫秒
PC时钟的分辨率约为18-20ms,Sleep()
和DateTime的结果。现在
将四舍五入到该值的倍数
因此,Thread.Sleep(5)
和Thread.Sleep(15)
将延迟相同的时间。这可能是20、40甚至60毫秒。你没有得到多少保证,Sleep()
的参数只是最小值
另一个占用CPU的进程(Chrome)(即使是一点点)也会以这种方式影响程序的行为。编辑:这与你所看到的相反,所以这里发生了一些其他的事情。不过,这是关于舍入到时间片的问题 基本上
Thread.Sleep(1000/60)
(其计算结果为Thread.Sleep(16)
),要求线程进入睡眠状态,并在16毫秒后返回。但是,该线程可能无法再次执行,直到经过更长的时间;比如说,32毫秒
至于为什么Chrome会产生影响,我不知道,但由于Chrome会为每个选项卡生成一个新线程,这将对系统的线程行为产生影响。这可能是因为Chrome(或Chrome的某些组件)调用的值会提高Windows API函数Sleep()的分辨率,它是从Thread.Sleep()
调用的
有关更多信息,请参阅此线程:
几年前,我在Windows Media Player中注意到了这种行为:我们的一个应用程序的行为会根据Windows Media Player是否正在运行而发生变化。事实证明,WMP正在调用timeBeginPeriod()
然而,一般来说,Thread.Sleep()
(并且扩展到Windows APISleep()
)是非常不准确的。只是一篇确认Matthew正确答案的帖子。Thread.Sleep()
的准确性受Windows上时钟中断率的影响。默认情况下,它每秒滴答64次,每15.625毫秒滴答一次。“Sleep()只能在发生此类中断时完成。这里的心理图像是由单词“sleep”引起的,处理器实际上处于睡眠状态,不执行代码。只有那个时钟中断会再次唤醒它以继续执行代码
您选择的1000/60
非常不愉快,需要16毫秒。只比15.625多一点
,所以你总是会在至少2个节拍后醒来:2 x 15.625=31毫秒
。你量的
然而,中断速率不是固定的,它可以由程序改变。它通过调用CreateTimerQueueTimer()
或传统的timeBeginPeriod()
来实现。一般来说,浏览器都需要这样做。制作GIF动画这样简单的事情需要更好的计时器,因为GIF帧时间是以10毫秒为单位指定的。或者一般任何与多媒体相关的操作都需要它
程序这样做的一个非常丑陋的副作用是,增加的时钟中断率会对整个系统产生影响。就像在你的节目里一样。你的计时器突然变得准确,你实际上得到了你要求的睡眠时间,16毫秒。所以Chrome正在改变速率,大概是每秒1000个滴答声。支持的最大值。当你有一个竞争对手的操作系统时
您可以通过选择与默认中断率更接近的睡眠持续时间来避免此问题。如果你要求15,那么你会得到15.625,而Chrome无法对其产生影响。31是下一个最佳点。等等,15.625的整数倍并向下舍入。不要使用DateTime
进行诊断测试。改用秒表。@Adam Plocher Chrome运行时线程速度是Chrome的两倍,当我关闭它时,它会立即变慢。这里没有问题要解决。睡眠意味着“至少睡这么长时间”,这就是它的作用。当你让一根线睡觉时,它可能再也不会醒来;就肉眼所见,可能有更高优先级的线程。当你说睡眠时,线程调度程序有很大的自由度去做它喜欢做的任何事情,显然当Chrome运行时,它喜欢做一些不同的事情。为什么?谁能说呢?调度程序的行为与文档中描述的一样—它至少休眠了16毫秒—所以不要担心。如果您想知道实际发生了什么,而不是我的随机推测,那么我建议您从阅读Windows内部80页的线程调度算法描述开始如果你对这个主题感兴趣,那么第六版。更一般地说,用零以外的任何参数调用Sleep可能是一个bug。为什么你要花钱创建一个完整的线程,只是为了让它进入睡眠状态?你不会雇佣一个工人然后付钱让他们睡觉。线是昂贵的;如果你不打算使用一个,把它放回池中。我试过秒表,它给我的输出与DateTime相同。DateTime和线程计时器的分辨率基本相同——这并不奇怪——所以使用一个来计时另一个是一个非常糟糕的主意。是的