我对算法和性能基准测试比较陌生,但我有几个问题。
我一直在编写一种算法,希望能够一次以小迭代的形式进行处理,以限制对本已要求苛刻的流程循环的中断。我的目标是每次迭代的处理时间少于 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 问题(或任何支持多任务但不是实时操作系统的操作系统,它涵盖所有消费者操作系统)。所有常规的多任务操作系统都会为每个线程提供一段时间,让给定的线程可以不间断地运行,而不是可能切换到另一个线程。如果您的步骤的执行在中间暂停以支持由 Stopwatch
测量的其他线程时间,则本质上是线程等待继续执行的时间长度(在 Windows 中默认为 ~15ms)。
正确测量时间是一项艰巨的任务,通常最好留给专门的工具——分析器。
如果您希望仅通过进程内计时器获得略微更一致的测量 - 提高运行代码的线程的优先级。这样线程将有较低的机会被挂起以支持其他线程。
注意事项:
- 实时操作系统通常需要执行代码的一些合作以保证不间断的执行时间。我也不相信有这样的操作系统支持 C#。
- 即使在像 MS DOS 这样的非多任务操作系统中,您也可以看到类似的时间随机波动,因为操作系统必须处理来自设备(磁盘、键盘、计时器)的中断,因此主单线程代码的执行可以暂停中断处理代码的持续时间(通常时间很短,但问题仍然存在)。
- .Net 代码增加了一些额外的问题,因为它必须执行可能在任何时间点发生的垃圾收集(即由于在另一个线程上分配)。更多信息 Fundamentals of Garbage Collection .
关于算法中的 C# 性能波动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46367969/