计算机 · 十年

    大概是2000年的时候,我有了第一台计算机。那时电脑才刚刚普及,价格还是比较高的,我记得好像总价是5k5,那是七喜很低端的一款,赛扬400、64M内存、4G硬盘,在我的要求下升级到了128M内存和10G硬盘。其实我父母当时根本对电脑没任何概念,只知学这玩意对以后很有帮助,买电脑对当时我家的情况来说并不是一笔小的费用。只是再多的钱对于当时的我来说还只是一个数字,直到后来我才知道其实这不是一个容易的决定。所幸的是这部电脑产生了足够的价值,至少影响了我这十年的很多选择。

    刚开始接触电脑的时光令人难忘,因为我在头一个星期几乎天天都在重装系统。原因无他,就是我乱删Windows下的文件。在重装了几次系统好好反省了之后,好歹我算是搞明白哪些文件能删,哪些不能删。网上的人都说ME是个短命的系统,我头几年装的一直是ME,98没装过多少次,当时联想电脑有附送正版98光盘,我倒是借同学的盘来装过几次,但还是觉得没ME好用又换了回去,一直到XP出现。

    在Tiger的帮助下,我安装了VB6,开始接触简单的编程。从那时到现在确实有十年,只是说出去没多少人相信罢了,人家看你脸的时候其实已经给你扣了顶帽子,如果听到超出自己理解范围的,便认为你是在撒谎。或许我可以感到高兴,原来我还很年轻。VB是一本十分简单的语言,动态类型,窗口事件模型,调用WinAPI,令人印象最深刻的,是那即见即所得的图形控件开发环境。因为VB语法和QB几乎没差别,所以中学参加的计算机竞赛我都是用QB的,只是很不熟悉,从图形化编程到文本编程的痛苦可想而知。

    对于算法,我总是太较真。记得有次和Tiger一起去某个市参加比赛,有道题我想了大半天没做出来,但他做出来了,后来我问他怎么做的,他说是穷举,我相当无语,或许我打心底从没认为穷举算是一种算法,又或者我本来在算法方面并没有太多天赋……其实那时候做编程的题目还是挺有收获的,将一个问题,抽象到语言里描述,再到解决思路,最后是将思路转变成正确的代码,这个过程远比大学里去听几堂计算机的课要有用得多。也正是这个过程,让我在高考填志愿时,有自信即使不选计算机专业,而选自己感兴趣的其他专业,最后的计算机水平也不会比计算机专业出身的人水平差。高中的时候Tiger学pascal,我一看那一坨begin...end便没有半点兴趣,于是抽空自学了下C,只是由于学业的关系,在编程上花的时间其实并不多,所以在C这门神奇的语言上并没有什么实质性的收获。

    高考后对于我来说也是个解脱,因为考得不是很好,与浙大和华工无缘,家里人不希望我复读,我更不希望为了张更好的毕业证书浪费一年时间,所以就决定随缘去广工,从另一面来看,至少我大学可以过得很轻松。高考后的暑假时间比较多,我特地好好学了下AS,当时记得还只是Flash MX,也就是Flash7+AS2的时代。当时的Flash已经可以做很多的东西,简单的三维投影在Flash4的时候已经有开源代码了,只是当时我看不懂就放了一边,直到大一到图书馆借了本书,书名是《Flash MX编程与创意实现》。这是一本对我影响很深刻的书,我对OOP的理解正是从这本书开始的:为什么写代码要拆分模块,为什么要保护私有数据,怎样实现代码的重用。虽然这本书没有直接说这些东西,但是我看到的却是面向对象思想的影子。AS2只是个脚本语言,没有类,没有继承,通过原型,一样可以使用OOP的方式解决问题。对我来说,这就好比开了一扇门,让我看到了更广阔的世界。其实那本书的内容我还给图书馆的时候就看完了,但后来我还是在网上买了一本全新的放着,权当纪念。

    大学时候我加入了计算机协会,成了名干事,后来还挂名当了年软件部部长哈。其实当初加入时根本不知道干事是做啥的,进去后才晓得原来就是组织活动,纯打杂的。计协的会员很多,干事却很少,加上新校区很多东西都不完善,组织活动也挺不容易。印象比较深的是装机比赛吧,那一个汗,拿奖那几个家伙哪是装机,根本就是拼。打开机箱是吧,用力一拍,开了,那一个神速。因为比赛规则是要求螺丝安装正确,能正常开机自检,速度快者胜。要是真有谁谁谁听着某人是装机比赛前几名这种头衔让他去这么装机的话,硬盘会不会折寿是个值得研究的问题。其实装机速度快慢根本没多少意义,快不到哪去,当时第一名好像就是我计时的,40多秒,正常装机的时间也多不了太多,正常人话几千块钱的东西没必要为了几分钟这么摧残吧……在计协我还认识了bosi,年纪轻轻就出了本黑客攻防的书,特牛X。在他介绍下我跟他做了两个项目,也正是从那时起我开始学习C#,还用了阵子MSSQL和VC++。

    当时还是VS.NET,C#已经足够吸引人:界面开发和VB一样方便,语法和C++类似,但因为没有指针所以简洁很多。其实C#也是有指针的,只是需要标为非安全代码。近两年我接触过不少人,说起C#就大言不惭说C#不支持指针,速度慢,心情好时就解释下其实C#也有指针,也有内存布局映射,心情不好就权当听了个笑话。自从用了C#后我基本没用VB了,当然Excel的VBA除外,我想我学C#确实是有6年的,在语言层面我还是敢在简历里写精通C#这几个字的。只是在COM互操作、WEB、非安全代码等方面没什么机会接触,C#在国内最常做的还是网站方面的,这也是我决定离开原来公司的一部分原因。C#方面的书我看过不少了,感觉写得最透彻的是《CLR via C#》,里面讲述的GC和线程方面的介绍让我收获不少。

    C#和Java很像,可能是历史原因也可能是平台原因,Java有大量框架和库,很多后来才移植到.NET里。但从语法来看,Java的语法相比C#实在是不敢恭维,Java的Lambda表达式语法着实让我汗如雨下,不知是不是不熟悉所导致的偏见。Java相比.NET,最大的问题应该是在IDE和系统支持上,自从做Delphi的那个谁去了MS,VS05之后IDE便让人感觉到项目开发也可以很容易。由于我一直用VS开发,偶尔用用Flash开发AS3的,对于Flash那脑残的代码开发环境便深深感受到,MS是做操作系统的,人机交互做的让人舒服,反而Expression那种做设计的却总像写代码;Adobe是搞设计的,自从Flash从MM转到Adobe名下之后的Flash9开始,界面是漂亮了,也多了很多智能的方案,敲代码却总是件让人纠结的事。直白点说,MS希望用户敲键盘,界面则点鼠标;Adobe希望用户所有事都用鼠标。Flex我没怎么用,不评价。Eclipse我最近两个月用来开发C++(VM+Linux),靠,这玩意竟然是人用的,用的直吐血。Netbean也用了下,十分汗颜,不支持Alt+鼠标列编辑的IDE竟然还能存活至今,也许高手们都喜欢用Emacs/Vim这类神器弹钢琴吧。系统支持上,Win7自带.NET3.5,Win8自带.NET4.5,Java一律要装JRE才可以运行。Java比.NET最大的优势应该还是在跨平台上,.NET要跨平台的话可以用Mono,但终究还是没有Java那么广泛,Android上的Mono似乎还要收费,真是无语。

    大多数的Java和.NET程序都是运行时进行JIT编译运行的,代码编译后是中间代码文件,首次运行时虚拟机将要执行的那部分中间代码转为本地代码,只是首次运行的时间会增加不少。计算机的平均性能每年都有很大提高,但近年来的发展方向有了改变,从一开始的单核追求高频率,到后来追求的多核追求高执行效率,如何让程序在多核下充分利用性能,与及如何在完成同样的任务下降低成本。前者驱动着并行计算的发展,后者则催生了云计算,国内的网速还是比较不堪入目的,所以对于云计算等方面我还是静观其变了。并行计算是个让我比较感兴趣的话题,人容易受传统思维定势所限,更容易理解顺序型的逻辑,并行是一门如何组织协作的学问,更强调整体效果。一年前我见China-pub上看到本介绍Erlang的书,介绍了这门面向并发和容错的语言。做过GSM网络的应该都对Erlang这个词不会陌生,那是爱立信乃至整个移动通讯行业关于话务量的单位,一个爱尔兰相当于一个用户连续打了一个小时的电话,爱立信的OMC是比较成熟的,文档很详尽,单看Alex给我感觉,爱立信是个比较务实的企业。至于国内的华为中兴,据我所知的是无稳定公开数据说明文档,提供的是中文包装过的管理页面,几乎没有多少接口是可供第三方分析参考的,纯一黑盒。由于这些原因我买了本Erlang的书来看,对这门语言感觉还是相当不错的:二进制字节解码相当相当的简单,基于消息的多进程模型,变量不可变的原则,和那诱人的模式匹配。由于没有合适的使用场景,我只是大致学了下Erlang的语言特性,没有过多的深入学习。

    后来.NET4.0也出了F# 2.0,从特点来看比较接近Erlang和Scala。只是我看了下之后,觉得语法很别扭,也可能是之前C#用得太熟又或者对Erlang的语法有先入为主的偏见。按我目前的理解,F#在语言上也是变量不可变,但却支持可变变量,其实因为F#依赖于底层的CLR和可使用BCL,就已经注定变量不可变只是一个约定而不是一个规范。F#只是在CLR上做了一层不可变类型,就像string类型或结构一样,改变赋值操作时创建新对象,再在多线程协作时规范下使用方式而已。底层是CLR和原生线程(估计是线程池线程),我很难想象这种方式对系统的负荷,因为.NET的1个线程就要保留1M的内存。是不是F#开了1000个线程就要占用1G内存? 我不知道。相比之下,据说Java一个线程是512k,而Erlang则是512Byte,汗,结果让我对Erlang的虚拟机实现有不少兴趣。

    从某些途径,我得知Erlang的上下文切换十分迅速,另外Erlang的进程调度器有个很重要的原则——绝对公平,就是说,当前有多少进程,每个进程获得的时间片都相等。从这两点我猜Erlang的调度是个循环,按每个固定的时间片调用一个进程就暂停,各进程没有优先级。而模式匹配的实现,估计是按Erlang的几大数据类型和匹配数量来进行,就像C++的重载函数名那样。侯捷有句话说得很好:源码面前,了无秘密。Erlang的源码是公开的,希望以后我能从中得到真正的答案。

    学习Erlang后,我学了下Python,语法很简单,有点像JS。Python语言里没有begin...end,没有end XXX,也没有{},语句块用相同空白缩进来标识,我发觉这是统一代码风格一个很好的办法,至少所有代码都会有同样的缩进,不会有些地方用tab有些地方用空格,有些地方{放在if后面,有些地方放在if下一行。代码编写的人越多,统一代码风格就越重要。关于Python我收获最大的是一本叫做《Python源码剖析》的书,书里介绍了Python的变量内存分配、函数调用原理、GC管理,线程协作全局锁等,都是些比较有深度和技巧的内容,对于架构设计提供了不少思路。为了保证变量状态统一,Python使用全局锁,虽然支持多线程,但是却不是真正意义上的并行执行,或许应该和LUA那样成为线程协作。为了利用多核CPU,Python一般会运行多个进程,各个进程用消息通讯的方式。回头一看,走的还是Erlang的老路。

    工作三年我了解得比较深的还有MySQL,主要是性能优化和查询表达方面。一个最常听的问题就是MsSQL和MySQL的主要差别是什么,MsSQL和.NET契合度很高,MySQL有丰富的存储引擎,Oracle没使用过不评论,Access?不评论。MySQL可以根据不同的场合混合使用不同的存储引擎,例如直接使用CSV引擎可以拿CSV当表来查询,使用InnoDB支持事务,使用Merge支持多表合并查询,还有一些支持列式存储的第三方引擎,如果对性能要求很苛刻,还可以自定义一个嵌进程序里,据说Adobe就用这种方式内部使用MySQL作为嵌入式数据库管理旗下个中软件的通讯。经常和人讨论时会发现不懂MySQL的在大谈特谈性能问题,例如分表肯定比合表快,InnoDB肯定比MyISAM慢等。其实性能优化不是纸上谈兵,如果不了解MySQL内部机制就随意优化,往往得不偿失,当然,如果不实际对比两种做法的真实性能,完全不会发觉这些问题。

    简单说下。分表和合表的查询性能,要看存储引擎、索引的命中率是否足够高、索引命中后的数据集大小、查询是否需要整个索引所包含的数据集。要考虑这点:分表查询时查询整个结果集需要N个查询,这N个查询代表N次文件IO和索引检索,由于分表的话索引应该是一样的命中率,也就是索引检索时间会变成单表的N倍。MyISAM的索引和数据文件是分开的,一般单表的索引大小和各分表的索引大小不会差距太大,这样的话分表的查询性能就很可能没合表的查询性能高。而对于InnoDB和MyISAM的性能,有一个关键的地方是两者查询时使用的索引类型是什么,InnoDB是聚集索引,数据跟主键是连续分布的,MyISAM也可以做覆盖索引,在非覆盖索引的情况下,访问行数据还要多一次寻址。另外InnoDB支持行锁定,MyISAM使用表锁定,在写高并发时,读性能会有影响,所以某些时候MyISAM的性能可能还不如InnoDB。

    在新公司开发网页游戏服务器已经两个多月,两个月C++,一个月LUA,一个月Erlang,收获不少。其实语言并不重要,重要的是语言背后的思想。我坚信对于同一个问题,不同语言会有不同的方案去解决,但思想很可能是不一样的,C++作为静态编译语言的代表,多态和模版可以很好的抽象游戏中的各类对象,只是照目前来看,公司里的C++代码更像是用C++的语法去写C的逻辑,模版几乎没什么用,函数类这种超级强悍的手段完全没见到。LUA是脚本语言的代表,语法特简单,调试比较惨,主要是客户端惨,因为服务端写一遍代码能通过语法检查太容易了,变量、函数名错误和很多基本错误都只能在运行时发现,并用trace的方式跟踪(因为是C++调用LUA,LUA里单步调试没成功),只能多测试了。Erlang的话,模式匹配用起来那是相当的爽,也可以动态反射执行,但因为不存在return这种直接跳转导致了case嵌套很严重,还好可以写些通用的辅助方法拆分逻辑,但一堆的fun还是看起来很凌,IDE不给力啊。Erlang使用尾调用,运行期函数调用关系会被消去不少,进程通讯时如果调试容易导致等待进程超时退出,ETS数据管理不当还是存在并发问题……有待解决的问题还有很多,相信我还可以从这里学到不少的东西,只是我更希望编程只是我的兴趣,而不是谋生的职业。

原文地址:https://www.cnblogs.com/neutra/p/2252061.html