我正在尝试创建一个间隔小于1ms的循环,使用TimeSpan
启动8000个刻度(1个刻度= 100ns,因此8000个刻度等于0.8ms或800us):
private static void MeasureAutoResetEvent()
{
TimeSpan interval = new TimeSpan(8000L); // 800us
double elapsed = 0;
Stopwatch watch = new Stopwatch();
AutoResetEvent autoResetEvent = new AutoResetEvent(false);
while (true)
{
watch.Restart();
autoResetEvent.WaitOne(interval);
watch.Stop();
elapsed = ResolveTicks(UoM.Microsecond, watch.ElapsedTicks);
Console.WriteLine(elapsed); // <- Does not writes ±800
}
}
UoM
枚举和ResolveTicks()
方法定义如下:
public enum UoM
{
Second,
Millisecond,
Microsecond,
Nanosecond,
}
public static double ResolveTicks(UoM uom, long ticks)
{
return
uom == UoM.Millisecond ? ticks * 1e3 / Stopwatch.Frequency :
uom == UoM.Microsecond ? ticks * 1e6 / Stopwatch.Frequency :
uom == UoM.Nanosecond ? ticks * 1e9 / Stopwatch.Frequency :
ticks * 1 / Stopwatch.Frequency;
}
我正在使用Stopwatch
来衡量autoResetEvent.WaitOne(interval);
使用的时间。但是,控制台的输出不会写入±800。有谁知道上面的代码有什么问题?
答案 0 :(得分:2)
这里的问题是.WaitOne()
只能精确到5到20毫秒(一般来说)。
当然,如果你试着等待800us,它就会无处可去。
.WaitOne()
的分辨率由当前Windows Timer Resolution确定。
答案 1 :(得分:1)
对于正常的日常使用,计时器足够精确,但不够精确。当你进入毫秒领域(或更糟糕的是,在它下面)时,任务切换机制变得有影响力。任务切换还取决于平台(Windows上的循环,Linux上的几个,取决于内核)。 Linux内核专门为RT(实时)应用程序编译,可以保证特定的响应时间(取决于硬件)。
假设您的代码是正确的并且您在Windows上运行,您可以尝试设置process priority to the highest level(实时)并固定核心,使其始终在同一核心上运行(以便各种L1,L2 ,L3 CPU缓存正确预热)。否则你会偶然发现由任务切换引起的抖动。