基准测试探险 - 性能高尔夫





5.00/5 (3投票s)
基准测试探险 - 性能高尔夫
最近,Stack Overflow 的开发者之一 Nick Craver 一直在 推特上发布代码片段,来自他们的源代码,上周发布了以下代码
Stack Overflow 代码库的每日截图(无需分配内存即可检查字符串中的标记)。#StackCode pic.twitter.com/sDPqviHgD0
— Nick Craver (@Nick_Craver) 2016年4月20日
这段代码是对你通常编写的代码的优化版本,专门编写以确保它不分配内存。此前,Stack Overflow 遇到过 .NET GC 导致的大型暂停 问题,因此,看来在适当的情况下,他们会尽力编写不进行不必要内存分配的代码。
我还必须感谢 Nick 让我了解了术语 “性能高尔夫”,我听说过 代码高尔夫,但没有听说过性能版本。
旁注:如果你想查看完整的讨论以及所有不同条目的代码,可以查看 这个gist。此外,为了真正深入了解最快版本实际上做了什么,我强烈建议查看 Kevin Montrose 的博文 “优化练习”,其中有一些非常酷的技巧,尽管此时他基本上是在编写 C/C++ 代码,而不是你认为的 C# 代码。
优秀的基准测试工具
在这篇文章中,我不会过多关注这个特定的基准测试,而是将它作为一个例子,来说明我认为一个好的基准测试库应该为你提供什么。完全免责声明,我是 BenchmarkDotNet 的作者之一,所以我承认我可能会有偏见!
我认为一个好的基准测试工具应该提供以下功能
基准测试脚手架
通过使用 BenchmarkDotNet,或者任何基准测试工具,你可以专注于编写基准测试,而不用担心准确测量代码的任何机制。这很重要,因为通常当有人在 Stack Overflow 上发布优化和配套基准测试时,一些评论会指出他们的测量结果为什么不准确或完全错误。
对于 BenchmarkDotNet 来说,这很简单,只需向要进行基准测试的方法添加一个[Benchmark]
属性,然后添加几行代码来启动运行即可。
[Benchmark(Baseline = true)] public bool StringSplit() { var tokens = Value.Split(delimeter); foreach (var token in tokens) { if (token == Match) return true; } return false; } static void Main(string[] args) { var summary = BenchmarkRunner.Run
它还为高级场景提供了一些工具,例如,你可以使用[Params]
属性装饰字段/属性,如下所示
[Params("Foo;Bar", "Foo;FooBar;Whatever", "Bar;blaat;foo", "blaat;foo;Bar", "foo;Bar;Blaat", "foo;FooBar;Blaat", "Bar1;Bar2;Bar3;Bar4;Bar", "Bar1;Bar2;Bar3;Bar4;NoMatch", "Foo;FooBar;Whatever", "Some;Other;Really;Interesting;Tokens")] public string Value { get; set; }
然后每个基准测试都将运行多次,Value
设置为不同的字符串。这为你提供了一种非常简单的方法来尝试不同输入的基准测试。例如,一些方法始终很快,而其他方法在对它们来说是最坏情况的输入上表现不佳。
诊断正在发生的事情
如果你声明优化代码的目的是“检查string
中的标记,**无需**分配内存”,你真的希望能够证明这是否属实。我之前写过关于 BenchmarkDotNet 如何 提供此信息,在这种情况下,我们得到以下结果(点击查看全尺寸图像)
所以你可以看到ContainTokenFransBouma
基准测试不是无分配的,在这种情况下这是一个问题。
一致、可靠和清晰的结果
另一个重要方面是你应该能够依赖结果。这部分是信任工具,希望随着时间的推移,人们会 信任 BenchmarkDotNet。
此外,你应该能够获得清晰的结果,因此除了提供易于粘贴到 GitHub 问题或 Stack Overflow 答案中的基于文本的结果表外,BenchmarkDotNet 还将使用 R 统计和绘图库 提供几个图表。有时,一大段文字并不容易解释,但彩色图表可以提供帮助(点击查看全图)。
在这里,我们可以看到原始的ContainsToken
代码在某些情况下“更慢”(尽管值得指出的是 Y 轴以纳秒为单位)。
摘要
我是否建议在日常场景中编写像这些优化一样的代码?不会。
毫无例外,优化的代码可读性较差,难以调试,并且可能包含更多错误。当然,当你到达 最快版本 时,你不再编写可识别的 C# 代码了,它基本上是伪装成 C# 的 C++/C 代码。
但是,为了学习、娱乐或仅仅因为你喜欢竞争,那就没问题。只要确保你使用一个像样的工具,让你能够专注于编写尽可能优化的代码的乐趣部分!
文章 基准测试探险 - 性能高尔夫 最初发表在我的博客 性能是一项特性! 上。
CodeProject