创建一个使用TimeSpan使用AutoResetEvent.WaitOne迭代1ms以下的循环

时间:2016-09-02 08:25:14

标签: c# windows

我正在尝试创建一个间隔小于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。有谁知道上面的代码有什么问题?

2 个答案:

答案 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缓存正确预热)。否则你会偶然发现由任务切换引起的抖动。