首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C#中对小代码样本进行基准测试,这种实现还能改进吗?

在C#中对小代码样本进行基准测试,这种实现还能改进吗?
EN

Stack Overflow用户
提问于 2009-06-26 03:50:00
回答 11查看 22.6K关注 0票数 111

因此,我发现自己经常对小块代码进行基准测试,以查看哪个实现最快。

我经常看到一些评论说,基准测试代码没有考虑到jitting或垃圾收集器。

我有以下简单的基准测试功能,我是慢慢发展起来的:

代码语言:javascript
复制
  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);
    }

用法:

代码语言:javascript
复制
Profile("a descriptions", how_many_iterations_to_run, () =>
{
   // ... code being profiled
});

这个实现有什么缺陷吗?这是否足以证明在Z迭代中实现X比实现Y更快?你能想出任何方法来改善这一点吗?

EDIT很明显,基于时间的方法(相对于迭代)是首选的,有没有人有时间检查不会影响性能的实现?

EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2009-06-26 11:45:30

以下是修改后的功能:根据社区的推荐,请随时修改这是一个社区维基。

代码语言:javascript
复制
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使用附加的调试器来停止其优化,即使在发布模式下也是如此。

票数 101
EN

Stack Overflow用户

发布于 2009-06-26 09:50:23

GC.Collect返回之前,最终定稿不一定会完成。终结器被排队,然后在单独的线程上运行。此线程可能在测试期间仍处于活动状态,从而影响结果。

如果您想要确保在开始测试之前已经完成了终结化,那么您可能需要调用GC.WaitForPendingFinalizers,它将阻塞,直到终结化队列被清除:

代码语言:javascript
复制
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
票数 23
EN

Stack Overflow用户

发布于 2009-06-26 04:18:53

如果你想把GC交互从等式中去掉,你可能想在GC.Collect调用之后运行你的“预热”调用,而不是在调用之前。这样,您就知道.NET已经从操作系统为您的函数的工作集分配了足够的内存。

请记住,您正在为每次迭代进行非内联方法调用,因此请确保将您正在测试的内容与空体进行比较。您还必须接受这样一个事实:您只能对比方法调用时间长几倍的事情进行可靠的计时。

此外,根据您正在分析的内容的类型,您可能希望在一定的时间内运行基于时间的计时,而不是特定的迭代次数--这可能会导致更容易比较的数字,而不必为最好的实现运行非常短的时间和/或为最坏的实现运行非常长的时间。

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1047218

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档