进程:当用户发出运行程序的命令时,就会生成一个进程。 同一个程序可以产生多个进程(一对多关系),以允许多个用户同时运行同一个程序而不会发生冲突。 进程需要一些资源来完成其工作,如CPU使用时间、内存、文件和I/O设备,并且它们是按顺序依次进行的,即每个CPU核在任何时候只能运行一个进程。
线程:是操作系统能够进行计算调度的最小单位。 大多数情况下,它包含在流程中,并且是流程中的实际操作单元。 线程是指进程中的单个顺序控制流。 一个进程中可以并发运行多个线程,每个线程并行执行不同的任务。 一个程序至少有一个进程,一个进程至少有一个线程。
进程和线程的区别:进程是计算机管理正在运行的程序的一种方式。 一个进程可以包含一个或多个线程。 线程可以理解为子进程。
首先,要实现多任务,我们通常会设计一个模式,负责分配任务和执行任务。 因此,在多任务环境中,通常有一个或多个。
如果用多进程来实现-,主进程是,其他进程是。
如果用多线程来实现-,主线程是,其他线程是。
多进程模式最大的优点是稳定性高,因为如果某个子进程崩溃,不会影响主进程和其他子进程。 (当然,如果主进程挂了,所有进程都会挂,但进程只负责分配任务,挂掉的概率很低)第一个也是最著名的就是多进程模式。
多进程模式的缺点是创建进程的成本较高。 在Unix/Linux系统下,调用fork是可以的,但是在Linux下创建进程的代价是昂贵的。 另外,操作系统可以同时运行的进程数量也是有限的。 在内存和CPU的限制下,如果有数千个进程同时运行,操作系统甚至会出现调度问题。
多线程模式通常比多进程快一点,但也快不了多少。 而且,多线程模式的致命缺点是,任何一个线程的死亡都可能直接导致整个进程崩溃,因为所有线程共享进程的内存。 在网上,如果某个线程执行的代码出现问题,经常可以看到这样的提示:“程序执行了非法操作,即将关闭”。 事实上,经常是某个线程出现了问题,但是操作系统会强制其结束。 整个过程。
在这种情况下,多线程比多进程效率更高,因此微软的IIS服务器默认采用多线程模式。 由于多线程的稳定性问题,IIS 并没有那么稳定。 为了缓解这个问题,IIS现在又出现了多进程+多线程的混合模式,这确实让问题变得越来越复杂。
不管是多进程还是多线程,只要数量大了,效率就肯定上不去。 为什么?
让我们打个比方。 假设你不幸正在准备中考,需要每天晚上做语文、数学、英语、物理、化学五门功课。 每份作业需要1小时。 如果先花1小时做语文作业,再花1小时做数学作业,然后依次完成,总共需要5个小时。 这种方法称为单任务模型,或者批处理任务模型。
假设您计划切换到多任务模型。 你可以先做语文1分钟,然后改做数学作业,做1分钟,再改做英语,以此类推。 只要切换速度足够快,这种方法的性能就和单核CPU一样。 多任务处理也是一样。 从一个幼儿园孩子的角度来看,你同时做五门科目的作业。
然而,改变作业是有代价的。 例如,从语文转到数学时,必须先把桌上的语文书和笔清理干净(这叫救场),然后打开数学课本,找到圆规和尺子(这叫准备)。新环境)。 )在开始做数学作业之前。 操作系统在切换进程或线程时是一样的。 它需要先保存当前的执行环境(CPU寄存器状态、内存页面等),然后为新任务准备执行环境(恢复上次的寄存器状态、切换内存页面等),然后才能开始执行。 这个切换过程虽然很快,但是也需要时间。 如果有数千个任务同时运行,操作系统可能主要忙于切换任务,没有太多时间执行任务。 这种情况最常见的就是硬盘发出疯狂的嘟嘟声,点击窗口没有任何反应,系统处于假死状态。 因此,一旦多任务数量达到极限,系统的所有资源都会被消耗掉。 这样一来,效率就会急剧下降,所有任务都无法很好地完成。
是否执行多任务的第二个考虑因素是任务的类型。 我们可以将任务分为计算密集型和IO密集型。
计算密集型任务的特点是需要大量计算,消耗CPU资源,比如计算圆周率、视频高清解码等,都依赖CPU的计算能力。 虽然这种计算密集型任务也可以用多任务来完成,但是任务越多,任务切换所花费的时间就越多,CPU执行任务的效率就越低。 因此,为了最有效地利用CPU,计算密集型任务的并发任务数应等于CPU核心数。
计算密集型任务主要消耗CPU资源,因此代码运行效率至关重要。 此类脚本语言运行效率非常低,完全不适合计算密集型任务。 对于计算密集型任务,最好用C语言编写。
第二类任务是IO密集型的。 涉及网络、磁盘IO的任务都是IO密集型任务。 这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远低于CPU和内存的速度)。 对于IO密集型任务,任务越多,CPU效率越高,但有一个限度。 最常见的任务是 IO 密集型任务,例如 Web 应用程序。
IO密集型任务执行过程中,99%的时间都花在IO上,很少时间花在CPU上。 因此,用速度极快的C语言替换如此速度极慢的脚本语言根本无法得到任何改进。 运营效率。 对于IO密集型任务,最合适的语言是开发效率最高(即代码量最少)的语言。 脚本语言是首选,C语言是最差的(对于此类任务处理)。
考虑到CPU和IO之间巨大的速度差异,任务大部分时间都在等待IO操作。 单进程和单线程模型将阻止其他任务并行执行。 因此,我们需要一个多进程模型。 或者是多线程模型来支持多个任务的并发执行。
现代操作系统对IO操作做了巨大的改进,最大的特点就是支持异步IO。 如果充分利用操作系统提供的异步IO支持,可以使用单进程单线程模型来执行多个任务。 这种新模型称为事件驱动模型。 Nginx是一个支持异步IO的Web服务器。 它在单核 CPU 上运行。 使用单进程模型可以有效地支持多任务处理。 在多核CPU上,可以运行多个进程(数量与CPU核心数相同),充分发挥多核CPU的优势。 由于系统中的进程总数非常有限,操作系统的调度非常高效。 使用异步IO编程模型来实现多任务处理是一个大趋势。
与语言相对应,单线程异步编程模型称为协程。 在协程的支持下,可以基于事件驱动编写高效的多任务程序。