使用AutoResetEvent创建迭代低于1ms的循环.等一下TimeSpan
本文关键字:TimeSpan 一下 循环 创建 AutoResetEvent 迭代 1ms 使用 | 更新日期: 2023-09-27 18:05:32
我正在尝试创建一个间隔小于1ms的循环,通过使用具有8000个节拍的TimeSpan
启动(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
enum和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。有人知道我上面的代码有什么问题吗?
这里的问题是.WaitOne()
只精确到5到20毫秒之间(一般来说)。
当然,如果你想等800秒,那就差远了。
.WaitOne()
的分辨率由当前Windows定时器分辨率决定
对于日常使用来说,计时器足够精确,但不是完全精确。当您进入毫秒级(或者更糟,低于毫秒级)时,任务切换机制就变得有影响力了。任务切换还取决于平台(Windows上是轮询,Linux上有几个轮询,具体取决于内核)。有些Linux内核是专门为RT(实时)应用程序编译的,可以保证特定的响应时间(取决于硬件)。
假设你的代码是正确的,并且你在Windows上运行,你可以尝试将进程优先级设置为最高级别(实时)并固定核心,以便它总是在同一个核心上运行(以便各种L1, L2, L3 CPU缓存被正确预热)。否则,您会陷入由任务切换引起的抖动。