C#中那些[举手之劳]的性能优化

隔了很久没写东西了,主要是最近比较忙,更主要的是最近比较懒……

其实这篇很早就想写了

工作和生活中经常可以看到一些程序猿,写代码的时候只关注代码的逻辑性,而不考虑运行效率

其实这对大多数程序猿来说都是没有问题的

不过作为一只有理想的CodeMonkey,我还是希望给大家分享一些性能优化心得

曾经在网上听过这样一句话

程序的可读性和性能是成反比的

我非常赞同这句话,所以对于那些极度影响阅读的性能优化我就不在这里赘述了

今天主要说的就是一些举手之劳即可完成的性能优化

 减少重复代码

这是最基本的优化方案,尽可能减少那些重复做的事,让他们只做一次

比较常见是这种代码,同样的Math.Cos(angle) 和Math.Sin(angle)都做了2次

优化后

还有另一种 ,在方法中实例化一个对象, 但是这个对象其实是可以复用的

优化后

还有一种是不必要的初始化,比如调用out参数之前,是不需要初始化的

这里的new User()就是不必要的操作,

优化后

不要迷信正则表达式

正好在第一个栗子里说到了正在表达式(Regex)对象就顺便一起说了

很多人以为正则表达式很快,非常快,超级的快

虽然正则表达式是挺快的,不过千万不要迷信他,不信你看下面的栗子

有多少人认为正则表达式比较快的,举个手??

rgwerg2314rvgerger25338811040

结果为10w次循环的时间 ,即使是10个Replace连用,也比Regex好,所以不要迷信他

ConvertQuot1:3518
ConvertQuot2:12479

最后给你们看一个真实的,杯具的栗子

合理使用正则表达式

上面说了正则表达式的效率不高,并不是说就不要用他了,至少正则表达式的作用不仅仅如此而已

如果一定要用正则表达式的话也需要注意,能静态全局公用的尽量全局公用

注意他的第二个参数RegexOptions.Compiled 注释是  指定将正则表达式编译为程序集。这会产生更快的执行速度,但会增加启动时间。

通俗的说就是加了这个枚举,会使得初始化Regex对象变慢,但是执行字符串查找的时候更快, 不使用的话,初始化很多,查询比较慢

之前测过相差蛮大的 ,代码就不比较了,有兴趣的可以自己试试相差多少

另外还有一些枚举项,不确定是否对性能有影响,不过还是按规则使用会比较好

  • RegexOptions.IgnoreCase    // 指定不区分大小写的匹配,  如果表达式中没有字母,则不需要设定
  • RegexOptions.Multiline         // 多行模式。更改 ^ 和 $ 的含义….  如果表达式中没有^和$,则不需要设定
  • RegexOptions.Singleline       // 指定单行模式。更改点 (.) 的含义….  如果表达式中没有.,则不需要设定

让编译器预处理常量的计算

编译器在编译程序段的时候 如果发现有一些运算是常量对常量的,那么他会在编译期间就计算完成,这样可以使程序在执行时不用重复计算了

比如

ewfwefwef231449524591669

不过编译器有的时候也不是那么聪明的

ergegege231453256152482

这个时候就需要我们帮助一下了

yhrhr231453426932297

给他加一个括号,让他知道应该先计算常量,这样就可以在编译期间进行运算了

字符串比较

这个可能很多人知道了,但还是提一下

1,2最慢 3较快 4,5最快

1,2几乎没区别 4,5几乎没区别

不过这个只适用于比较null和空字符串,如果是连续的空白就是string.IsNullOrWhiteSpace最快了,不过这个方法2.0里面没有

所以2.0可以这样 (s+””).trim() == 0

这里的关键就是 s + “”  这个操作可以把null转换为””

注意第二个参数只能是””或string.Empty 这样的累加几乎是不消耗时间的,如果第二个参数是” “(一个空格)这个时间就远远不止了

字符串拼接

字符串累加,这个道理和Regex一样,不要盲目崇拜StringBuilder

在大量(或不确定的)string拼接的时候,StringBuilder确实可以起到提速的作用

而少数几个固定的string累加的时候就不需要StringBuilder 了,毕竟StringBuilder 的初始化也是需要时间的

感谢残蛹 博友提供的说明

ps: 这段我确实记得我是写过的来着,不知道怎么的,发出来的时候就不见了…..

rghergerer231515097401697

此外还有一个string.Concat方法,该方法可以小幅度的优化程序的速度,幅度很小

他和string.Join的区别在于没有间隔符号(我之前常用string.Join(“”,a,b,c,d),不要告诉我只有我一个人这么干)

另一种经常遇到的字符串拼接

对于这种情况有2中优化的方案

对于3.5以上可以直接使用Linq辅助,这种方案代码少,但是性能相对差一些

对于非3.5或对性能要求极高的场合

bool类型的判断返回

这种现象常见于新手程序员中

类型的判断

一般类型的判断有2种形式

1,这种属于代码比较好写,但是性能比较低, 原因就是GetType()的时候消耗了很多时间

2,这种属性写代码麻烦,但是性能很高的类型

其实有个中间之道,既可以保证性能又可以比较好写

大部分情况下 这个是可以用的 如果你自己有个类型实现了IConvertible,然后返回TypeCode.Int32 就不再这个讨论范围之内了

使用枚举作为索引

下面这个是一个真实的例子,为了突出重点,做了部分修改,删除了多余的分支,源代码中不只4个

优化后

不过有的时候,枚举不一定都是连续的数字,那么也可以使用Dictionary

这种优化在分支比较多的时候很好用,少的时候作用有限

字符类型Char,分支判断时的处理技巧

这部分内容比较复杂,而且适用范围有限,如果平时用不到的就可以忽略了

在处理字符串对象的时候,有时会需要判断char的值然后做进一步的操作

这里有一种空间换时间的优化方式, 虽说是空间换时间,但是实际浪费的空间不会很多,因为char最多只有65536长度

原先仅特殊符号一部分就需要判断12次,修改过后只判断一次就可以得到结果了

这方面的栗子在我的Json组件(代码)(文章1,2,3)中也有使用

 摘取部分blqw.Json的代码

结束了…还要后续吗?…貌似我又要懒一段时间

我写的文章,除了纯代码,其他的都是想表达一种思想,一种解决方案.希望各位看官不要局限于文章中的现成的代码,要多关注整个文章的主题思路,谢谢!

1 收藏 2 评论

相关文章

可能感兴趣的话题



直接登录
最新评论
  • 判断力有没有   2014/04/06

    Switch-case转换成跳转表的那个例子确定编译器做不到吗?C/C++的编译器常做这个吧

  • Jerry Weng   2014/04/08

    既然看到了,说两句,除了正则表达式那块,其他都表示赞同。
    博主把正则表达式和Replace比较,意义不大,说的难听点,就好比把杀猪刀和水果刀比较。正则表达式在做简单字符匹配的时候,或许没有很大优势,但是正则表达式的绝对优势在于复杂的搜索模式,举个例子,在一段字符里找到封闭在和的子字符串,或者找到所有以下格式的字符串:,并输出id,name,target各是多少。想象下,不用正则表达式怎么做?而且性能的比较不能简单的拿自己能想到的简单场景去比较,这种结果只能做简单参考,而不能做指导意见。
    术业有专攻,不能迷信是对的,能在合适的场景用最合适的方法,才是NB之道。

跳到底部
返回顶部