话说大半年没有更新blog了,本想把libevent系列继续下去的,但是想想,这种代码级别的东西还是自己看源码来得实在。所以这个libevent系列就往后延吧!搞程序也4年多了,总觉得自己太过拘泥于细节,陶醉于细节,致使对一些框架级别的东西视而不见。花个半天时间思考一下,还是能从过去的经验中总结出一些框架层次的东西的,总结的过程其实就是跳出细枝末节,概括一通吧。
网络程序就是可以发送网络请求或者接受网络请求的程序(亦或二者皆有),真正要实践一下网络编程,最好的方法就是自己尝试写一个proxy(最好的,没有之一),网络程序基本上都是用吞吐量来衡量性能(吞吐量可以是处理的事务数,可以是处理的字节数),网络程序的吞吐量在我看来有三个因素决定:程序自身的架构,系统平台的架构,硬件平台。我们作为应用开发,应该从程序自身架构,和硬件平台的角度来提升程序的吞吐量。好的网络应用程序的吞吐量在硬件资源线性扩展时应该也是以近乎线性规律地增加。归根结底,取决于应用本身的架构。
现有架构有多进程架构,多线程架构,事件驱动(状态机)。
多进程架构中连接和进程是一对一的关系,一个进程服务一个连接,譬如apache web server,这儿不过多地强调多进程框架的有点。这个框架的缺点是并发能力差,也许对于进程这种重型的内核资源,你可以使用进程池来抵消创建时的开销,但是随着进程的增多,频繁的进程上下文切换会拖累整个系统,导致并发能力差。
多线程架构中连接和线程是一对一的关系,一个线程服务一个连接。多进程架构的有点恰恰是多线程架构的缺点,多线程创建速度快,而且线程间切换也快,从这个方面讲多线程框架多半会比多进程框架的并发能力强。然而,多线程无法避免的各种同步锁却总是让看似高效的多线程程序的性能大大低于理论值。即使linux的线程模型是多对一,但是由于网络程序的特殊性(所有的并发连接都会阻塞在不同的地方),会将多对一的线程模型退化成一对一的线程模型,这样几乎和多进程模型相差无几了。
事件驱动(状态机)框架中单进程处理多个处理,本质上网络程序是由数据驱动的。事件驱动使用非阻塞的系统调用完成异步的网络IO,每收到一个IO事件就进行处理,变换状态。每个状态的变换点类似于线程切换,其实事件驱动就是模拟多线程。为了能更好地利用硬件并行性能,可以创建和cpu核心数相关个数的进程,每个进程实现状态机。其实事件驱动是有悖人的正常思维的,所以开发难度不小。如果能有一个库,能模仿多线程的调用接口来完美地实现事件驱动,那就可以说是集三个框架的优点于一身了。