今天,我想跟大家聊一聊C#的性能优化,当然,这里并不谈基本的原则,这些都假设你已经非常精通了,本文聊的是要争取几个毫秒的程序。关于基本的性能优化,可以参考园子里的文章。比如:
先说说我的测试环境:
一台典型的笔记本电脑,Windows 7中文版,.net Framework用的是4.5版本,VS是现在VS11 beta版。我也是用VS2008这样的环境测试了下面的所有场景,发现没有任何区别,所以就以VS11为基准了。
所有测试数据都是编译为Relase,且不包含PDB,直接双击运行而非在VS环境下执行。点击这里下载源代码。
言归正传,先测试第一点:
静态方法比实例方法快吗?
我们总是从各个渠道听说:静态方法比实例方法要快,所以,我想亲自试试。测试方法很简单,循环调用实例方法和静态方法。
/// <summary> /// 这是一个普通类,调用实例的方法 /// </summary> public class C1 { public void DoLoop() { for ( int i = 0; i < int .MaxValue; i++) { DoIt(); } } private void DoIt() { } } /// <summary> /// 使用静态方法调用。 /// </summary> public static class C2 { public static void DoLoop() { for ( int i = 0; i < int .MaxValue; i++) { DoIt(); } } private static void DoIt() { } } |
测试结果如下:
测试多次,基本偏差不大,只能说,静态方法比实例方法快那么可怜的一点点,鉴于实例方法的灵活性远大于静态方法,所以还是一般使用实例方法吧。
也实验过,在方法中访问实例字段和静态字段,发现也没有区别,所以不再单独罗列代码。
避免方法内创建实例的情况
这个要讨论的问题有点难说明,我们还是先看一看.net内部的代码吧,下面是一段Collection<T>.Add的方法:
1 2 3 4 5 6 7 8 9 | public void Add(T item) { if ( this .items.IsReadOnly) { ThrowHelper.ThrowNotSupportedException(ExceptionResource.NotSupported_ReadOnlyCollection); } int count = this .items.Count; this .InsertItem(count, item); } |
注意ThrowHelper类,如果换成我们自己写,一句话就搞定了:throw new NotSupportedException。为什么微软要这么写呢?
老外有解释:Why does SortedList implementation use ThrowHelper instead of throwing directly?
其实,我也是信奉此真理,而且就在前一段时间,一位同事还找我问,两段几乎一样的代码,为什么测试性能有差距,结果我按照此原理,将异常抛出放在外面,结果真的变好了。
现在,我还要再次测试一下,我相信的是数据:
class C1 { private Dictionary< int , int > _dict = new Dictionary< int , int >() ; public C1() { _dict.Add(1, 1); _dict.Add(2, 2); } public void Do1() { object obj = new object (); for ( int i = 0; i < int .MaxValue/100; i++) { GetItOne(1); } } //这个方法,在内部可能创建实例 private int GetItOne( int key) { int value; if (!_dict.TryGetValue(key, out value)) { throw new ArgumentOutOfRangeException( "key" ); } return value; } public void Do2() { for ( int i = 0; i < int .MaxValue/100; i++) { GetItTwo(1); } } //这个方法,将创建实例的代码移动到外部 private int GetItTwo( int key) { int value; if (!_dict.TryGetValue(key, out value)) { ThrowArgumentOutOfRangeException(); } return value; } private static void ThrowArgumentOutOfRangeException() { throw new ArgumentOutOfRangeException( "key" ); } } |
测试结果是:
基本上,会快0.06秒左右,但是如此大的循环得到的好处并不是那么的明显,但有作用。这种写法还是比较舒服的,所以还是建议大家用吧。
下篇我将实验:数组的枚举,类和结构创建的成本。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构