因此,我发现自己经常对小块代码进行基准测试,以查看哪个实现最快。
我经常看到一些评论说,基准测试代码没有考虑到jitting或垃圾收集器。
我有以下简单的基准测试功能,我是慢慢发展起来的:
static void Profile(string description, int iterations, Action func) {
// warm up
func();
// clean up
GC.Collect();
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < iterations; i++) {
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
用法:
Profile("a descriptions", how_many_iterations_to_run, () =>
{
// ... code being profiled
});
这个实现有什么缺陷吗?这是否足以证明在Z迭代中实现X比实现Y更快?你能想出任何方法来改善这一点吗?
EDIT很明显,基于时间的方法(相对于迭代)是首选的,有没有人有时间检查不会影响性能的实现?
发布于 2009-06-26 11:45:30
以下是修改后的功能:根据社区的推荐,请随时修改这是一个社区维基。
static double Profile(string description, int iterations, Action func) {
//Run at highest priority to minimize fluctuations caused by other processes/threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
// warm up
func();
var watch = new Stopwatch();
// clean up
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
watch.Start();
for (int i = 0; i < iterations; i++) {
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.Elapsed.TotalMilliseconds);
return watch.Elapsed.TotalMilliseconds;
}
确保在启用了优化的情况下在发行版中进行编译,并在Visual Studio之外运行测试。最后一部分很重要,因为JIT使用附加的调试器来停止其优化,即使在发布模式下也是如此。
发布于 2009-06-26 09:50:23
在GC.Collect
返回之前,最终定稿不一定会完成。终结器被排队,然后在单独的线程上运行。此线程可能在测试期间仍处于活动状态,从而影响结果。
如果您想要确保在开始测试之前已经完成了终结化,那么您可能需要调用GC.WaitForPendingFinalizers
,它将阻塞,直到终结化队列被清除:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
发布于 2009-06-26 04:18:53
如果你想把GC交互从等式中去掉,你可能想在GC.Collect调用之后运行你的“预热”调用,而不是在调用之前。这样,您就知道.NET已经从操作系统为您的函数的工作集分配了足够的内存。
请记住,您正在为每次迭代进行非内联方法调用,因此请确保将您正在测试的内容与空体进行比较。您还必须接受这样一个事实:您只能对比方法调用时间长几倍的事情进行可靠的计时。
此外,根据您正在分析的内容的类型,您可能希望在一定的时间内运行基于时间的计时,而不是特定的迭代次数--这可能会导致更容易比较的数字,而不必为最好的实现运行非常短的时间和/或为最坏的实现运行非常长的时间。
https://stackoverflow.com/questions/1047218
复制相似问题