戴毅朋友是老朋友了,多思,善问,而且问的问题都很有挑战性,逼得我自己也不得不勤于思考,有这么一位好朋友,是我的荣幸。
我前面的一篇帖子《Windows程序员如何转向Linux开发应用?》就是专门回答他的,最近他又提问,我这里再次作答。
为了让大家看清楚来龙去脉,我把我们的邮件往返粘贴在这里,请大家参考。
一家之言哈,欢迎拍砖!
===============================================================
戴毅:
肖老师您好。
我从csdn学习大本营得到您的信息。不好意思打搅您。
我现在用c++在linux下开发大型应用程序。我想请教是否值得深入学习linux kernel。
我没有特别多的时间。另外我有多年Windows下开发应用程序的经验。
谢谢。
肖舸:
看你的应用了,如果需要碰触kernel,就学一点。不需要就算了。
我做Linux几年,也没怎么详细研究过kernel。因为我毕竟不需要写操作系统。
我原来也是做Windows的程序的,迁移没觉得有啥大问题。
 
戴毅:
非常感谢你花了这么多时间写了所有我想知道的信息。
既然找到了好老师,以后我就接着问下去了。
再次感谢。
戴毅:
 
肖老师您好。
我还想请教一个问题。
您在博客上多次提到c++/Linux跨平台的问题。ACE正好是针对这个问题的解决方案。例如您在工作中遇到的情况。
但是大多数情况下服务器都是使用同一种机器,如Linux。所以在这种情况下真的这么需要用跨平台的技术吗?
跨平台技术固然提供了面向对象的优点,但同时也可能在某种程度上对效率产生负面影响。
我是想知道是否值得花很多时间学习这种技术。
非常感谢。
===============================================================
戴朋友你好:
应该说,你的问题问得很刁钻,呵呵,我还真有点不好回答的感觉,这样,你的问题涵盖很多方面,我们一个一个来,别乱了。
第一个问题,ACE,其实是这样的,我知道ACE,也知道目前我开发的库很多都和ACE有功能重合的地方,事实上,在我准备的下一本书中,我将和“ACE”抢饭碗,呵呵,在数据传输方面做出一点探讨。你问我为什么不直接用ACE,这个问题就比较复杂了。
首先,我十年前开始开发自己的工程库的时候,ACE还没有出生呢,这个理由够不够充分?呵呵。
其次,ACE是基于纯C++的一套库,里面使用了大量的C++高阶特性,如继承,模板,这些特性在PC等大内存场合,应用很好很方便,但在arm9等嵌入式环境,由于系统一般只有64M内存,不足以支撑这些高阶特性,因此一般建议都不要使用。因为太过于复杂的模板和继承关系,其实是以消耗大量内存来实现的。
第三,ACE既然是基于C++的,不可避免使用异常,我在《0bug》书中讲过,我是不喜欢异常的,从来不用。原因很简单,一个库模块,如果使用了异常,相当于它的API很模糊,不仅仅包括.h文件中声明内容,还有很多使用者看不到的异常抛出,这些是隐含约定,除非使用者详细看过源代码,否则很难精确捕捉每一个异常。
这导致,这个API使用非常困难,假如使用者忘了,或者根本不知道捕捉某个异常,那么当某次真的该异常发生,由于无人捕捉,会层级上传,直到操作系统,而所有的操作系统对于这类应用异常的处理非常简单,kill process,杀掉进程。而我所从事的商用工程,一般都有7*24小时运行要求,这就相当于最大的bug了,挂了。
不过注意哦,异常并不是每次都出现,商用工程一般公网运营,很多时候实验室不可能模拟所有的运营情况,万一某个异常测试从来没有出现过,而库的使用者没有捕捉,那大家就等着挂吧。最要命的是,这类异常肯定不会留下记录了,因为进程都挂了,这类bug,无法跟踪,无法分析,实际上没有任何可解决之道,最后,大概只有两条路,一是让客户忍受,二是系统重构。
所以,我书中有讲,乱抛异常,很多时候还不如不抛,这类全靠使用者“人”来理解的API,不在编译时以程序行为界定,一般都有漏洞,因为人是最靠不住的,每个人都可能犯错误。一次内存泄漏,可能就是导致内存被吃点,但短期内服务不会中断,一次DoubleLock,最多是众多的服务线程中某一条挂死,服务资源减少,但服务业不会终止,但一次未捕捉的异常,相当于直接调用exit,服务立即终止,大家认为是不是这样?
因此,我一般建议,长期的商用服务需求,最好不要完全使用C++的特性,C++很多高阶特性,有点自己YY的意思,体现很强烈的学院派思想,就是程序员首先相信自己是不会犯错误的,然后大量使用抽象思维,写出来的程序并不直观,bug也无法控制,另外,对于并行开发,C++很多高阶特性其实支持并不好。比如很多模板库中,比如list,并未提示程序员插入数据是值传递还是地址传递,那么,如果我插入的数据中,有操作系统相关的锁变量的时候,值传递显然就是错误的,但程序员不知道啊,结果就是本来正确的程序,一用模板库就错。
综上所述,我一般习惯于不使用C++的很多现成库,因为无法满足我的使用要求。
第二个问题,为什么要研究跨平台。这要分几个方面讲。
首先,以后的社会,我认为会是“云+端”的社会,这点上我同意微软的意见,google虽然推出“云计算”,但请大家注意,他也在努力抓“端”,大家认为google推出手机,浏览器,操作系统,是在做什么?
以后的社会,我估计就是超大规模的中心计算集群,再加上生活中无处不在的各种小终端来为人们服务,PC作为特殊的品种,可能更多存在与专业的开发公司中,家庭中PC的比例会减少。玩游戏有专业的游戏机,上网有epc,嗯,还有各种MIID设备,当以后电视机都可以上网看新闻,发邮件,打网游,看网络电影,听音乐的时候,大家认为,普通的(不是我们IT专业的)家庭用户,单独购买一个PC机的可能性有多大?
因此,我认为以后一个程序员,一般会面临两方面的需求,就是“极大”和“极小”,这都需要技术积累,积累自己的工程库来应对。而一个程序员的寿命,很多时候都比一个公司长,也就是说,我们未来不知道自己会到哪个公司从事哪方面的开发,那么,如果我们不做积累,每个公司都从0做起,以后活起来是不是很累?
而如果我们针对自己从事的每个具体工作,都积累一个库,没有一个抽象出来,具有普适性的通用库,这种工程库的积累,会不会很累?也并不实际,大家说是不是?所以,作为程序员自身职业生命的需求,我要说,我们需要积累跨平台通用工程库,让自己的工作具有延续性,让自己的生活越过越轻松。
而且,一个工程库,一般说来不是开发完就完了,那真得有实际的商用工程,在公网上跑n年,没有bug,没有缺陷,才叫“工程库”,商用工程软件,一般说来最值钱的,不是这些代码本身,是这些代码经过大量测试,长期运营验证出来的一个稳定结果,那种每跳一个公司,就换套库的做法,其实不叫积累工程库,叫做自己YY。
现在明白了吧,我作为一个程序员,我有责任为自己准备一个经过长期稳定验证过的,可以支撑我以后大多数开发情况的工程库。
第三个问题,你担心效率,这是个问题,太通用的东西,确实效率不敢保证。但是,我要说,我自己的工程库,确实可以保障这一点。
这不是我说大话,原因很简单,“库是我的”。也就是说,我具有写库的能力,而且库代码,库体系架构对我全公开,我当然知道针对某个特定情况,应该怎么优化。比如我的队列,随手加个队尾指针,其效率立即提升成百上千倍,这在使用别人的库的程序员看来,是不可想象的。
嗯,还有单写多读锁,威力极大,我利用这个工具,把内存池的分配和回收效率,从每秒几百次,提升到50万次/秒,你认为这个效率又如何?
因此,我想强调,研究自己的工程库的另外一个好处,逼着自己深思,逼着自己去不断调整和优化,最终,使自己掌握成熟的工程开发思想,针对每个问题,见过的没见过的,能拿得出自己的解决方案,这才是最重要的。积累工程库,其实练的还是程序员自己。我中间的库代码,最多的一个翻写了39遍,请问,当我把一段代码翻写这么多遍后,它的逻辑对我还有什么秘密可言?我是不是当然知道怎么把它的性能调到最优,而且,还没有bug。你说对不?
简单举个例子吧,apache,大家都知道吧,但大家知道它的效率吗?恐怕很多人都说不出来,我恰好测试过一点。在4核8G内存的服务器上,apache承接每秒800个并发连接,大家觉得怎么样?是不是有点低?
我理解过一点apache的实现机制,认为它的子进程池做得那叫一个烂,很显然没有进一步抽象,工作任务与物理子进程绑定,系统上限是多少,它就是多少。我的工程库中,至少在线程池的基础上,进一步抽象出任务池,任务于物理执行体分离,这说明什么?我的任务池每秒钟翻牌效率27500次(赛扬1.4G的,512M内存的一台老笔记本),理论上,我承接的并发连接数是,每秒27500次,大家又认为如何?当然,实际工作我们给的值偏保守,一般承诺每秒6000次左右,基本没有问题。所以我常说,apache的程序员需要study。
这些并不是我吹牛,核心代码我都share在我的书里面了,大家有兴趣,可以自己敲出来测试一下就知道了,计算机是最公正的,乱写程序,大师写的代码照挂,做事情仔细认真,小菜鸟也能写出漂亮的工程代码,至少我就是这么认为的。大家同意不?
其实这里也说一点我自己的想法,我一直有点委屈,这么多年,凭什么好技术都是外国人的?我们中国人就一点创新能力都没有?我个人是不服这口气的,凭什么外国人放个屁都是香的?我倒真想做一点程序出来,让外国人看看中国人的程序能力。
我这么想了,也这么做了,现在share出来,请大家看看,不想说我这个人水平怎么怎么地,但是,至少我想为中国人争口气。
大家的意见呢?会不会觉得我无聊?
===============================================================
这是某位朋友的回复:
自己能写出库,老师牛啊。不过还是比较支持用c++标准类库,设计标准类库人就经过严格的测试来给客户端的程序员的,有时候写程序,从软件复用的角度来讲,我比较支持用标准的东西。
=======================================================
 
我的回答:
首先,下面这段话是由感而发,并不是针对这位朋友,我还是很同意标准的,不过,对于标准的理解,我有自己的一点看法。
标准库不是不能用,但是,如果我们做的应用,标准库中没有提供,我们是不是可以考虑,针对自己的需求,写一点库呢?
事实上,很多时候标准库是不合用的。
举个简单例子,MFC提供CSocket类,知道不?
大多数时候,它是阻塞式工作,也就是说,当它等待接收时,线程会被挂住,直到报文到来。
这就带来一个问题,一个线程只能等待一个Socket的接收,那么,Windows下开2000个线程,差不多是安全的,是不是说,我们准备的服务器,最大只能支持并发2000呢?
这显然不符合实际使用需求,很多时候,我们对服务器的需求,远高于这个指标。
当然,使用Select,IOCP技术,可以大幅度改变这个能力,我这里仅仅是举例子。
很多时候做工程化开发,一旦做细了,你会发现标准库提供的特性,这也不合适,那也不合适,要么,你将就它,你做的东西受它的指标限制,要么,你自己弄,轻易就可以远远超过它的指标,你怎么选?
市场化竞争,体现差异化生存,如果你和你的竞争对手都使用同一标准库开发,是不是就像现在的公版显卡,公版mp4,公版笔记本一样,产品没有任何差异性和特色,那么,好卖不好卖?
就我这么多年对IT业的了解,目前市面上很多卖的好的产品,做得好的公司,其实很多就没有按照标准库来,都是自己开发一套的。
google就不说了,它推自己的操作系统,自己的浏览器,我就奇怪,大家怎么不骂他重复造轮子?反而觉得它好用?
SONY是另外一个例子,walkman,vaio系列电脑,哪个是用公版做的?都是自己造,造的很有特色,造就了一代家电“贵族”。
我很佩服这类善于打破传统,不因循守旧的公司的。
我这篇文章,其实没有说完全,我觉得到这里就说到点子上了。
强调标准没错,我们的产品,凡是和别人接口的地方,一定要标准,这才能与一个大市场接轨,比如耳机插口,3.5mm的就比2.5mm的通用,这要遵守标准。
但是,遵守标准遵守到,在自己的产品内部,不敢做任何一点创新,任何东西,别人不做,自己不敢做,那就太过分了,没有创新,不管企业还是人,其实都死路一条。
我的理解,标准的遵守,应该是以与市场接轨,切入市场为原则,并不是为了限制住自己的手脚,不去开发创新性新产品。
另外,我也确实发现有很多研发人员,由于缺乏责任心和职业道德,做事情得过且过,一切以按部就班,不求有功,但求无过为原则,这时候,他们口中的遵守标准,其实已经成为逃避工作责任,不思进取,不肯创新,的借口而已,这就更要不得了。我希望CSDN学生大本营的同学,最好以后不要这样做。
当我们在批评别人重复造轮子的时候,小心一点哦,也许,等人家的轮子造出来,你拍马都追不上了。
那时候,你会怎么样?饿死?