Sam*_*ron 104 .net c# performance profiling
经常这样我发现自己对小块代码进行基准测试,看看哪个实现最快.
我经常看到基准测试代码没有考虑到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);
}
Run Code Online (Sandbox Code Playgroud)
用法:
Profile("a descriptions", how_many_iterations_to_run, () =>
{
// ... code being profiled
});
Run Code Online (Sandbox Code Playgroud)
这个实现是否有任何缺陷?是否足以表明实现X比Z迭代实现Y更快?您能想出任何可以改善这种情况的方法吗?
编辑 很明显,基于时间的方法(与迭代相反)是首选,是否有人有任何实施时间检查不会影响性能?
Sam*_*ron 93
这是修改后的功能:根据社区的建议,随意修改它的社区维基.
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;
}
Run Code Online (Sandbox Code Playgroud)
确保在Release中编译并启用了优化,并在Visual Studio外部运行测试.最后一部分很重要,因为即使在发布模式下,JIT也会附加调试器来限制其优化.
Luk*_*keH 22
最终确定不一定在GC.Collect
返回之前完成.终结排队,然后在单独的线程上运行.在测试期间,此线程仍可能处于活动状态,从而影响结果.
如果要确保在开始测试之前完成最终化,那么您可能需要调用GC.WaitForPendingFinalizers
,这将阻塞,直到清除终结队列:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Run Code Online (Sandbox Code Playgroud)
Jon*_*upp 15
如果您想要将GC交互排除在等式之外,您可能希望在GC.Collect调用之后运行"预热" 调用,而不是之前.这样你就知道.NET已经从操作系统为你的功能的工作集分配了足够的内存.
请记住,您正在为每次迭代进行非内联方法调用,因此请确保将要测试的内容与空体进行比较.您还必须接受,您只能可靠地计算比方法调用长几倍的事情.
此外,根据您正在分析的内容类型,您可能希望基于运行一段时间而不是进行一定数量的迭代 - 这可能会导致更容易比较的数字必须有一个非常短的运行以实现最佳实施和/或非常长的运行以实现最佳实施.
我完全避免传递代表:
导致闭包使用的示例代码:
public void Test()
{
int someNumber = 1;
Profiler.Profile("Closure access", 1000000,
() => someNumber + someNumber);
}
Run Code Online (Sandbox Code Playgroud)
如果您不了解闭包,请在.NET Reflector中查看此方法.
我认为像这样的基准测试方法要克服的最困难的问题是考虑边缘情况和意外情况.例如 - "两个代码片段如何在高CPU负载/网络使用/磁盘抖动/等情况下工作".他们是伟大的基本逻辑检查,看是否有特定算法的工作显著比另一个更快.但是要正确测试大多数代码性能,您必须创建一个测试来测量特定代码的特定瓶颈.
我仍然说测试小块代码通常几乎没有投资回报,并且可以鼓励使用过于复杂的代码而不是简单的可维护代码.编写清晰的代码,其他开发人员或我自己6个月后可以快速理解,比高度优化的代码具有更多的性能优势.
归档时间: |
|
查看次数: |
18957 次 |
最近记录: |