ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # 进程 vs. 线程 我们介绍了多进程和多线程,这是实现多任务最常用的两种方式。现在,我们来讨论一下这两种方式的优缺点。 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常是一个Master,多个Worker。 如果用多进程实现Master-Worker,主进程就是Master,其他进程就是Worker。 如果用多线程实现Master-Worker,主线程就是Master,其他线程就是Worker。 多进程模式最大的优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。(当然主进程挂了所有进程就全挂了,但是Master进程只负责分配任务,挂掉的概率低)著名的Apache最早就是采用多进程模式。 多进程模式的缺点是创建进程的代价大,在Unix/Linux系统下,用fork调用还行,在Windows下创建进程开销巨大。另外,操作系统能同时运行的进程数也是有限的,在内存和CPU的限制下,如果有几千个进程同时运行,操作系统连调度都会成问题。 多线程模式通常比多进程快一点,但是也快不到哪去,而且,多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。在Windows上,如果一个线程执行的代码出了问题,你经常可以看到这样的提示:“该程序执行了非法操作,即将关闭”,其实往往是某个线程出了问题,但是操作系统会强制结束整个进程。 在Windows下,多线程的效率比多进程要高,所以微软的IIS服务器默认采用多线程模式。由于多线程存在稳定性的问题,IIS的稳定性就不如Apache。为了缓解这个问题,IIS和Apache现在又有多进程+多线程的混合模式,真是把问题越搞越复杂。 # CPU-bound(计算密集型) 和I/O bound(I/O密集型) 我们可以把任务分为计算密集型和IO密集型。 计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。 计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。 IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。 IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。**对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差**。 # 异步IO 考虑到CPU和IO之间巨大的速度差异,一个任务在执行的过程中大部分时间都在等待IO操作,单进程单线程模型会导致别的任务无法并行执行,因此,我们才需要多进程模型或者多线程模型来支持多任务并发执行。 现代操作系统对IO操作已经做了巨大的改进,最大的特点就是支持异步IO。如果充分利用操作系统提供的异步IO支持,就可以用单进程单线程模型来执行多任务,这种全新的模型称为**事件驱动模型**,Nginx就是支持异步IO的Web服务器,它在单核CPU上采用单进程模型就可以高效地支持多任务。 **在多核CPU上,可以运行多个进程(数量与CPU核心数相同),充分利用多核CPU**。由于系统总的进程数量十分有限,因此操作系统调度非常高效。用异步IO编程模型来实现多任务是一个主要的趋势。 # 如何优化 网卡、硬盘都由南桥芯片控制,并属于中、低速设备,所以,在服务器上进行网络通讯、网络传输、磁盘读写均受南桥控制,此类即为IO操作。 IO密集型服务/业务即是以网络请求压力大、磁盘读写频繁的操作类型,当进行这些IO密集型操作时,CPU的负载相对较低(现代计算机均集成了对硬件访问控制的操作逻辑,使得CPU从这些操作中解放出来,提高核心资源的利用率)。 计算密集型,可以理解为在北桥芯片与CPU之间的通讯较高的服务/业务,往往这类操作常见的都是以计算为主的,而计算又是CPU/GPU的专长。 对于服务器,通过开发的服务或是业务,可以在项目之初就根据需求来对资源进行预先估算,大致属于IO密集型还是计算密集型的业务,并进行项目前期的资源预算等工作的开展,也包括前期的设计和后期的优化。 1. 项目立项过程中,根据需求对应的资源负载类型,提出对服务资源的需求配置 IO密集型的需求,一般来说,如果是磁盘读写频繁,通过对磁盘进行升级,提高磁盘的响应速度和传输效率或通过负载技术,将文件读写分散到多台服务器中;如果是网络请求负载较高,可以通过负载均衡技术,水平扩展服务,提高负载能力;或使用代理缓存服务器,降低核心服务的负载压力。 计算密集型的需求,首先可以考虑使用计算能力更好的CPU,然后考虑通过消息队列或其它降维算法,将计算分散的不同的计算结点,进行处理。 2. 项目开发时,进行合理的规划和业务开发 于IO密集型的需求,在开发过程中,就要考虑尽可能减少IO开销,**对磁盘读写频繁的业务,可以考虑通过内存缓存将热数据缓存起来,减少磁盘的请求**。 对于计算密集型的需求,在开发过程中,需要注意计算算法的优化及结果重用,并尽可能进行降维处理,比如通过某种算法将原业务需求的计算分散成可拆分的逻辑,并分散计算进行结果求解,最后进行组合(很像现在大数据处理里的一些模式,可以参考),或通过消息队列将大量的计算请求分发到其它的计算结点上去。 # 参考 [如保理解IO密集型服务和计算密集型服务](http://ju.outofmemory.cn/entry/214931)