本来我是要继续写我的foreach系列文章的另外两篇的。但是看了评C#事件处理,有一些感触。
我不同意大家关于语言越低级,运行效率就越高的说法。
语言越低级,编译器能够决定的东西就越少,就越不能很好的优化执行代码。大家想想为什么c语言编译器,一般都忽略register关键字,C++一般都忽略inline关键字? 很多时候,编译器只要掌握了足够的信息,就能做出明智的决定。
以前我测过delphi和C++生成的代码,delphi的代码比C++高效得多。因为C/C++里广泛使用了指针,对于变量的位置,struct中各个成员的排列方法,调用约定,对于编译器都有非常严格的限制。编译器只能忠实的翻译,错失了很多优化代码的机会。为了能够享受各种代码优化技术,C++编译器都提供了非常多的编译优化选项,但是绝大部分都不是100%安全的。因为C/C++程序员总是可以越权完成很多低级操作。比如:用const修饰的变量是不会被修改的,编译器可以利用这个知识将这个变量的值缓存在寄存器中。但是在C++中,就不能做这项优化,因为C++程序员可以强制cast掉const限制。也许大家认为编译器能够监测到这种cast,自动关掉这项优化,但是谁能保证其它.obj文件里的代码有没有修改这个const变量呢?
同样类的私有成员,在C++中也很难真正实现访问跟踪。编译器没有100%确信的知识,怎么能去优化呢?
世界上最好的汽车是手工打造的,但是不是说手工打造的汽车就一定比工业批量造出的汽车好。
我想写程序最重要的是如何最清晰的表达我们要解决的问题,而不要过多的体现解决问题的次要细节。我们要的是报表、订单;而不是内存,指针,函数。如果我们能从更高、更抽象的层次描述问题,就会留给底层软件更多发挥的空间。比如底层软件可以选择低运行效率,极高开发效率的方法完成功能,而快速的制作原形,展示设计;或者底层软件选择高速运行的策略,面向运行时间要求高的场合;或者选择低内存占用作为目标,等等。
规则不是约束创造性地力量,而是激发创造性地基础。没有稳定的规则,哪里会有什么创造?我认为.net规则,是激发创造的开始,是一个新的世界的开始。
有人质疑C#完成事件模型太隐晦,臃肿,和il不直接对应,太复杂。event关键字完成了多播事件、异步事件。想想java为了实现多播事件,明确的使用了列表。虽然C#也使用列表实现多播,但是使用列表这个事实并没有明确的在语法上体现出来。这有什么不同呢?这当然不同!在delegate中只有一个函数指针时,这个列表是不生成的,而且调用也是直接的,并没有一个调用循环。另外,C#通过delegate还可以实现异步事件,统一了异步I/O的编程模型,最近Ado.net也执行异步执行sql语句了。Java事件的interface实现,要完成异步事件不知道要使用多少代码。而且只要代码一旦写成,它就死了,运行环境就不能再做进一步的优化了。
比如做出租车,如果告诉司机你的目标地点,司机就可以综合道路的长度、拥堵情况、路况情况选择一个优化解。相反,如果告诉司机你的路线,那么一切都固定了,僵化了,司机拥有再多的知识,都无法用上了。高级语言和低级语言之间的差别就和这个现实生活的例子是一个道理。也许很多人不同意,认为自己既是乘客也是司机。但是你认为自己真的对所有的计算机知识都了解吗?CPU的不同,Cache效率的不同,总线效率的不同。硬件影响软件的要素已经非常多,软件的影响就更多了。现代的软件会依赖大量的操作系统的调用、库函数调用、编译器等等,谁能知道在数以万计的函数中,那一个效率高,那一个效率低。我们优化了数周代码获得的性能提升,会被一个设计糟糕的库函数轻易吞没。就算优化好了一个系统,换一个环境还是效率高的吗?比如用户机器更换了显卡驱动程序?谁都不会有能力做一个好司机。
让真正拥有实际运行知识的C#语言、.net运行环境来替我们完成95%的性能优化吧,我们能做一个好乘客,说清楚我们的目的地,就是极大的成功了。