刚看到一篇很有意思的文章,讨论对c# 4.0中dynamic特性的误用。我非常同意作者的观点,随着c#的发展,语法也渐渐变的复杂,无论处于炫耀,跟风,还是对语言特性本身的理解不足,被误用的情况正越来越多。当然每个人的角度不一样,看法也不同,由于我编写的大部分是实时程序,大部分代码要以每秒60次以上的频率运行,所以对性能更加敏感,这里仅仅是我的个人看法。不怕你笑话,至今为止我的代码大部分还是以1.0或者2.0的风格编写。可以说1.0以后,大部分语法进化都是以编写更简洁的代码为目标,以更少的代码,完成更多的任务,这当然是人人都期待的。可惜这些特性大多不是从语言本身的基础进化而来,包括委托推断,匿名方法,var等等,而是通过对编译器的扩展。天下没有免费的午餐,代码也是一样,虽然通过新特性,我们少写了很多代码,但并不意味着就少执行了很多代码,只是这些少写的代码由编译器帮我们生成了而已,更有甚者,某些看似简单的表达式,编译器要生成比手动优化更多的代码来实现。隐藏的复杂性是可怕的,但更可怕的是并不是所有程序员都能意识到这些潜在的复杂性,他们用这些语言新特性编写着代码,却不知道所写的代码"究竟干了些什么"。
举个例子,对于同样的代码Button.Click += new EventHandler(AddClick)和Button.Click += AddClick。对于后一种写法,很多人看到时只会想到“我们订阅了一个事件”,但对于第一种写法则会想到“我们*创建*了一个委托,并且订阅了事件”。New在这里非常有警示作用,告诉我们这行代码创建了对象,有额外的内存开销!更进一步,你在编写高频率程序时就不会写出这样的代码,因为即使是最微小的内存分配,以每秒60次调用时,短时间内也可能消耗海量内存,或者创建海量的garbage。当然,相信有经验的程序员都不会犯这样的错误,但是谁能保证当项目达到一定规模,当我们已经习惯了新语法带来的便捷之后,就不会出现类似的问题呢?因此老式的语法虽然复杂,但能更清晰的提醒你*你在干什么*。
再来看看4.0中的dynamic,关于它的优点就不说了,beta以来已经有铺天盖地文章进行了介绍,但问题是你是否真的就应该马上使用dynamic,把已有代码转变为dynamic风格?纵然dynamic极大提高了编写代码了灵活性,但同样也增加了出错的几率,更不要说相应的性能损耗。就连Anders本人也说过,他还是更偏向静态语言。看过很多人抱怨ms更新步伐太快,其实这并不意味着我们必须以相同的速度更新,新特性只是给了我们更多选择而已,究竟需不需要,还要根据实际情况选择,如果静态的c#足以满足目前需求,那么就完全没有必要去关心dynamic(当然,我并不是反对多学一些知识)。在时间,精力都有限的情况下,盲目跟风是很不明知的。
对于4.0来说,我最感兴趣的还是对线程管理和GC的优化,以及Parallel Programming(pp)。显然,两者都是和性能相关的,实际上我本来还写了一篇关于pp的文章,不过最后没有发,这里做个简短的说明吧。不可否认,pp将是未来革命性的编程方式,不过有2个原因让我放弃了把pp应用的现在的引擎中,1,Task对象无法复用,当Task执行完一段程序以后,如果要执行同样的操作,则必须创建一个新task对象。2,无论Task还是Parallel For都会带来一定的内存分配(看,这又是隐藏的复杂性)。正和之前的委托例子一样,无论把task还是Parallel For应用到游戏引擎主循环中,都意味着很大的GC压力,很难确定在复杂情况下到底能获得多少性能提升。PP作为目前4.0中的全新技术,和DLR一样,都还不完全成熟,ms的东西总是要等到第三版才能用,实在没必要急着用:)