在正式进入Python并发编程的相关类库、语法的介绍之前,还是继续来对并发编程中的几个核心概念做进一步的阐述说明,从而在理念上对后续的学习有一个全局性的指导。同时,简单介绍一下Python中的并发编程模型,后续的关于Python并发编程的文章,将重点围绕并发编程模型进行展开。
本文的主要内容有:
1、并发编程中的三个核心概念
2、Python中的并发编程模型
并发编程中的三个核心概念在上一篇文章中,我们简单介绍了并发和并行的概念,简单回顾一下:
1、并发是一个更加宽泛的概念,并发的概念中包含了并行的范畴,并行是并发的一种特殊形式。
2、并发可以是交替执行,也可以是同一时刻同时在运行。单个单核CPU,只能实现交替执行的并发。多核CPU或者多个CPU,才能实现同一时刻的并行。
3、由于分时复用的资源调度,以及流水线技术的存在,即使是单核CPU,也能实现广义上的并行,其实是指令执行阶段用到的不同CPU组件在并行工作。
本文要重点介绍的三个概念,分别是:程序、进程、线程。
我们写的代码从保存到硬盘到最终执行主要会涉及到以下过程:
1、代码编写完成后,以文件的形式保存在硬盘上,所以程序是静态的概念,就是我们编写的代码序列、源码文件。
2、程序开始执行之前,首先从硬盘加载到内存中,会创建对应的进程控制块(Process Control Block,PCB),用于标识进程的PID,进程相关的状态管理,进程所需要的内存资源的分配等。
3、每个进程会对应一个或者多个线程,每个线程同样会有对应的内存结构,叫做线程控制块(Thread Control Block,TCB)。用于标识线程的状态、调度线程的执行等。
4、每个进程中都会有一个线程为主线程,一般是我们代码中包含main()函数的入口文件,用于启动一个进程的执行。
5、如果进程中有多个线程,其他线程都是通过主线程的执行被不断创建、执行的。
6、操作系统中的进程/线程调度程序,负责基于相应的调度策略,给要执行的线程分配CPU资源,从而真正调度执行。
7、进程、线程执行完成,会销毁对应的PCB、TCB,回收相关的内存资源。如果涉及到内存空间不足时,还会涉及到需要把进程对应的内存临时置换到虚拟内存(其实是硬盘空间)中。下次被激活、调度执行时,再切换进入内存中。
对这个过程有个大概的了解即可,有感兴趣的,可以查阅相关的《操作系统》的书籍进行进一步深入学习。
一个完整的CPython进程大概是下图这样的,这里就不展开了。
基于以上的过程,我们再来简单区分一下程序、进程、线程这三个概念,我觉得有以下几点认知,暂时就足够我们进行后续的学习了:
1、程序是一个静态的概念,程序是储存在硬盘文件中的一行行代码的集合,可以简单对应为我们编写的源文件。
2、进程是一个动态的概念,进程有自己的状态管理、切换,进程从创建到销毁有一个生命周期的概念。进程是基于程序进行创建的,在内存中的一个数据结构。在操作系统的语义中,进程是资源分配的基本单位,这里面更加强调的是内存资源。
3、线程是一个动态的概念,线程可以理解为进程中的一个执行序列,线程是真正被动态执行的实体。每个进程可以有一个线程或者多个线程,每个进程都会有一个唯一的主线程,作为真正被CPU执行的入口序列。不同于进程作为内存资源分配的基本单位,线程是CPU资源分配的基本单位,也可以描述为调度执行的基本单位。
关于概念的基础,简单就聊这些,相信有上过《操作系统》课程的同学,应该有更加深入、全面的理解。
Python中的并发编程模型接下来,从全局上简单介绍一下Python中的并发编程模型。
在Python中主要有4种并发编程模型,需要说明的是,我们是在CPython实现的语境中,其他Python实现可能会有一些差异。
1、Threading模型
多线程模型,对应到Python中的内置库是threading,这种模型可以支持并发,但是无法支持并行,主要原因在于GIL的设计。
2、Multiprocessing模型
从字面意义上,也就是多进程了,对应的Python内置库是multiprocessing,这种模型支持并发语义,同时也支持真正的并行。
3、Async模型
对应到Python中的内置库是asyncio,即异步IO的相关支持。这种模型也是只支持并发语义,而不支持并行。
4、Subinterpreters模型
对应到Python中的内置库是subinterpreters,Python子解释器的概念,相当于变相突破了GIL的限制。这种模型支持并发语义,也支持并行。
通过表格简单比较下这4种并发模型:
本文就先介绍到这里了,关于这些并发编程,在后面的文章中将会逐一展开。
总结本文简单介绍了程序到执行的一个大概的过程,辨析了程序、进程、线程的概念,同时简单介绍了Python中的并发编程模型。
感谢您的拨冗阅读,希望对您有所帮助。