python之进程、线程和协程

定义

进程

进程是每一个应用运行起来都会有自己的进程,因为进程是系统资源分配的基本单位。直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。

每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
每一个进程创建出来,都会分配三种基本的内存资源,分别是代码段、数据段和堆栈段。
代码段和数据段分别保存着应用的执行代码和全局变量、常量、静态变量,这些就是不会变化或者很少变化的内容,当然内存占用相对也会比较少。
而应用运行起来,需要的更多资源就会在堆栈中用到。
其中堆空间是存放各种变量数据的地方,内存大小也是可以动态调整的。
而栈空间是子任务(线程、协程)独立存放自己的数据地方,比如:函数调用、参数、返回值和局部变量。
进程切换只发生在内核态,两步:1 切换页全局目录以安装一个新的地址空间 2 切换内核态堆栈和硬件上下文。 另一种说法类似:1 保存CPU环境(寄存器值、程序计数器、堆栈指针)2修改内存管理单元MMU的寄存器 3 转换后备缓冲器TLB中的地址转换缓存内容标记为无效。

线程

线程有时被称为轻量级进程(Lightweight Process,LWP),是操作系统调度(CPU调度)执行的最小单位。

线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。

操作系统不仅仅维持一个进程表,而且还会维持一个线程表,这样操作系统就可以把线程作为调度单位。

线程是进程内创建,可以共享进程的资源,所以,线程自身独立的资源依赖就会少很多,因为只需要为每个线程分配独立的栈空间。

而线程的栈空间是固定大小的,如果程序比较复杂,或者里面的数据量大,为了不出现“栈空间不足”的错误,就必须把栈空间设置的足够大才行。

协程

协程是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。是一种用户态的轻量级线程

协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

联系和区别

联系

1、一个进程可以有多个线程,一个进程也可以有多个协程。
2、一个程序至少有一个进程,一个进程至少有一个线程
3、一个线程上可以有多个协程

区别

1、进程切换需要的资源很最大,效率很低
2、进程和线程都是同步机制,而协程是异步
3、和线程比较,协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
4、进程和线程是有操作系统来控制切换的,协程不需要

通俗描述

有一个老板想要开个工厂进行生产某件商品(例如剪子)
他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程
只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程
这个老板为了提高生产率,想到3种办法:
在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式