算法中的 C# 性能波动

C# performance fluctuation in algorithm

我对算法和性能基准测试比较陌生,但我有几个问题。

我一直在编写一种算法,我希望能够一次处理小迭代,以限制对已经要求很高的流程循环的中断。我的目标是每次迭代的处理时间低于 1 毫秒,因此具有相当一致的性能似乎非常重要。

不幸的是,在应用进程权重将算法平均为 0.5 毫秒后,我偶尔会达到超过 20 毫秒的时间。我确实注意到数据收集会导致一些问题(我假设它在内存中移动?)我已经解决了这些问题但仍然会出现一些性能波动。

所以我在这里画了一个空白的方法。即使在这里,我偶尔也会遇到这些高潮。

    public void DoTask()
    {
        for (int i = 0; i < 100000; i++)
        {
            //do nothing
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        DoTask(); //burn

        var watch = new Stopwatch();
        watch.Start();

        double time;
        for (int j = 0; j < 20; j++)
        {
            for (int i = 0; i < 1000; i++)
            {                   
                time = watch.ElapsedTicks;

                DoTask();

                time = watch.ElapsedTicks - time;

                LongestTime = Math.Max(LongestTime, time);

                TotalTime += time;

                Count++;
            }
            double avgTime = TotalTime / Count;

            MessageBox.Show($"Longest time: {ToMs(LongestTime).ToString("#.##")} Avg time: {ToMs(avgTime).ToString("#.##")}");
            TotalTime = 0;
            Count = 0;
            LongestTime = 0;
        }
    }

Longest time: 13.04 Avg time: .01

发生这种情况的原因是什么?这是我无法控制的事情吗?

谢谢。

实际上更多的是 Windows 问题(或任何支持多任务但不是实时 OS 的操作系统,涵盖所有消费者 OSes)。所有常规的多任务操作系统都会给每个线程一段时间,给定的线程 运行 不会中断,并且可能会切换到另一个线程。如果你的步骤的执行在中间暂停以支持由 Stopwatch 测量的其他线程时间基本上是线程等待继续执行的时间长度(在 Windows 中默认为 ~15ms) .

正确测量时间是一项艰巨的任务,通常最好留给专门的工具 - 分析器。

如果您想要 稍微 仅使用进程内计时器获得更一致的测量 - 提高 运行 是您的代码的线程的优先级。这样线程将有较低的机会被挂起以支持其他线程。

备注:

  • 实时操作系统通常需要执行代码的一些配合以保证不间断的执行时间。我也不相信有这样的 OS 支持 C#。
  • 即使在像 MS DOS 这样的非多任务处理 OS 中,您也可以看到类似的时间随机波动,因为 OS 必须处理来自设备(磁盘、键盘)的中断, 定时器),因此主单线程代码的执行可以在中断处理代码的持续时间内暂停(通常时间很短,但问题仍然存在)。
  • .Net 代码增加了一些额外的问题,因为它必须执行可能在任何时间点发生的垃圾收集(即由于在另一个线程上分配)。更多信息 Fundamentals of Garbage Collection.