1.3 进程与线程
在对Python类和对象有了一定了解之后,我们还需要了解进程与线程。对于进程与线程,这里不会局限于Python语言层面,而是从操作系统层面展开介绍。进程与线程是入门Python高并发编程必须掌握的基础知识。
1.3.1 进程与线程的区别和联系
进程(Process)是计算机中的基础运算单元,是CPU统筹计算机中所有任务的程序实体。CPU通过对不同进程进行调用,协调位于寄存器、运算器以及内存中计算机任务的时间片,使每个计算机任务都能得到合理执行和调用。
线程(Thread)是计算机任务的具体执行者,是操作系统能够进行运算、调度的最小单位。线程隶属于一个具体的进程。在同一时刻,一个进程可以拥有一个或多个线程,线程是开发者可以直接与计算机CPU或内存进行交互的最小单位。
在操作系统(泛指Windows系统或Linux系统)中,进程指的是CPU调度的程序实体,线程是具体程序实体的执行者。一个进程可以包含多个线程,但是一个线程只能从属于一个具体的进程。一个线程不能跨进程存在,但是一个进程中的线程可以通过技术手段访问或操作另一个进程中的线程。
下面通过画图的方式来阐述进程与线程在Python项目中的存在方式,如图1-6所示。
图1-6 进程与线程在Python项目中的存在方式
一个具体的Python项目可以表示为一个进程,即Python项目启动之后,就会在计算机中以一个具体的进程存在,并且由计算机操作系统管理。当启动Python项目时,根据Python虚拟机(或解释器)解析Python语言的规范,Python虚拟机会创建一个专门用于解析Python语言的主线程,接着会创建一个专门用于执行Python语言所定义的任务的工作线程,即一旦Python项目正常运行起来,在计算机中就会存在一个Python主线程和至少一个工作线程。如果是多线程的业务场景,Python就会创建出多个工作线程来并发执行任务。
1.3.2 线程的7种状态
任何一个具体的Python线程拥有7种不同的状态。这7种不同的状态构成了线程的生命周期。
● 线程创建状态:该状态表明线程刚刚被创建,还没有被调用或初始化,此时的线程只是一个空的线程对象。
● 线程就绪状态:在该状态下,初始化一些线程运行所需要的属性和方法,以便被任务调用。
● 线程运行状态:线程实际运行的状态,即线程一旦被任务调用,就会从线程就绪状态转变为线程运行状态,且线程一旦进入运行状态,就表明已经开始执行任务了。
● 线程中止状态:当线程在运行状态时,由于任务中止或者人为操作等迫使线程停止运行,线程从运行状态转变为中止状态。转变为中止状态的线程,如果没有人为干预,不会自动执行,除非给线程设定一定的饱和策略或其他可恢复线程执行的策略条件。
● 线程等待状态:线程等待状态分为无限期等待状态和限期等待状态。无限期等待表示CPU资源被先前的线程抢占,且先前的线程一直不释放CPU资源,导致当前线程无限期等待下去;限期等待表示先前已经抢占到CPU资源的线程,在过了一定时间后会自动释放CPU资源,当前线程只需要等待一定时间即可获取CPU资源。线程运行状态无论转变为无限期等待状态还是转变为限期等待状态,均需要开发者控制,线程无法自动转换。
● 线程阻塞状态:线程阻塞状态与线程等待状态类似,只不过线程阻塞状态更多地用于表示线程队列的状态,即在线程队列中,等待执行任务的线程均可以被认为是阻塞的。线程阻塞状态需要开发者控制,线程无法自动转换。
● 线程结束状态:该状态表明当前线程已经执行完毕,这里所说的执行完毕包括线程已经执行完任务,或者线程在转变为中止状态之后,又转变为结束状态。线程可以在程序执行完后转变为结束状态,也允许开发者手动结束当前线程而转变为结束状态。
为了更清楚地说明线程状态,以及线程各状态间的转换,笔者画了一张线程状态转换图,如图1-7所示。
图1-7 线程状态转换
读者可以根据上面描述的线程状态,对比线程状态转换图来更好地理解线程状态及线程状态间的转换关系。