点击上方蓝色字体,关注公众号【程序员的一天】,
了解更多编程技术!
"喜欢的就去争取,得到了就珍惜!"亲爱的小伙伴们,大家好!欢迎关注《Python3 进阶系列之并发编程》!上一篇,我们说到Python实现并发的方式有:多进程、多线程、协程。相信大家都知道,进程、线程、协程是什么;但,尝试去解释这些概念时,可能就说不清楚了。今天,我们就一起来说一说:什么是进程、线程、协程?重在理解,部分内容如果目前不太清楚,也没必要过分纠结。有些东西,说不清道不明,但是使用多了,慢慢的就懂了!一起来看看吧~
本文内容⊙代码与程序的关系
⊙cpu和程序执行
⊙什么是进程
⊙什么是线程
⊙什么是协程
本文篇幅较长,大家可以选择性阅读!
01代码与程序的关系代码,相信大家都很熟悉,我们几乎天天都在写代码,读代码。小王吧,你写的python代码有bug!老王吧,你写的python程序有毒!在上面的对话中,并没有严格区分代码和程序的含义。
平时说习惯了,我们也都能理解,均指的是".py"文件。但,其实代码是代码,程序是程序,代码和程序是两个不同的概念。为了后面更容易理解进程,我们要区分代码和程序!代码:
指我们用开发工具所支持的语言编写出来的源文件,如,“.py”文件。
这时候的文件,也叫做“源代码”文件,是人类可读的。
程序:
是指令和数据的集合,可以被计算机识别和执行。
它可以作为目标文件(即:可执行文件)保存在磁盘中,或者作为内存段存放在内存地址空间中。
计算机无法识别高级语言编写出来的代码,所以当我们想运行源代码时,就需要一个“转化”的过程,来把高级语言编写的代码转变成计算机能读懂的机器语言。机器语言(machine language)是用二进制代码表示的计算机能直接识别和执行的一种机器指令的集合。
这种指令集,又称机器码(machine code),是计算机CPU可直接解读的数据。这个过程可以分成两类:编译、解释。因此,高级编程语言也对应的分为两种类型:编译型语言、解释型语言。编译型语言编写的代码执行之前,先会通过编译器对代码执行一个编译的过程,把代码转变成机器语言。运行时不需要再翻译,直接执行就可以了。最典型的例子就是C语言。解释型语言没有这个编译的过程,而是在运行的时候,通过解释器对代码逐行作出解释,然后直接运行,如,Python语言。02cpu和程序执行cpu(中央处理器)是计算机系统的运算和控制核心,承担了所有的计算任务,是信息处理、程序运行的最终执行者。cpu,时刻都在运行着!它本质是一块有输入和输出的大型集成电路,属于芯片的一种,大概长这样:
程序要想被执行,首先需要加载到内存,然后由cpu执行内存中的机器指令。cpu的工作可以分为5个阶段:1、取指令
2、指令译码
3、执行指令
4、访存取数
5、结果写回这部分知识不是本系列重点内容,如果展开,恐怕几天几夜也说不完... ...如果大家想深入了解,可以自行百度,网上有很多相关文章~
我们这里为了方便大家理解后续内容,仅仅简单介绍,如下:1、取指令阶段
取指令(Instruction Fetch,IF)阶段,是将一条指令从主存中取到指令寄存器的过程。
主存,又叫主存储器,是计算机硬件的一个重要部件,其作用是存放指令和数据,并能由CPU直接存取。
2.指令译码阶段
取出指令后,计算机立即进入指令译码(Instruction Decode,ID)阶段。
在指令译码阶段,指令译码器按照预定的指令格式,对取回的指令进行拆分和解释,识别区分出不同的指令类别以及各种获取操作数的方法。
3、执行指令阶段
在取指令和指令译码阶段之后,接着进入执行指令(Execute,EX)阶段。
此阶段的任务是完成指令所规定的各种操作,具体实现指令的功能。
4、访存取数阶段
根据指令需要,有可能需要访问主存,读取操作数,这样就进入了访存取数(Memory,MEM)阶段。
访存取数阶段的任务是:根据指令地址码,得到操作数在主存中的地址,并从主存中读取该操作数用于运算。
5、结果写回阶段
作为最后一个阶段,结果写回(Writeback,WB)阶段把执行指令阶段的运行结果数据“写回”到某种存储形式。
结果数据经常被写到CPU的内部寄存器中,以便被后续的指令快速地存取。在指令执行完毕、结果数据写回之后,若无意外事件(如结果溢出等)发生,cpu就接着获取下一条指令,开始新一轮的循环。我们之前说过,cpu是按时间片,交替执行不同的任务。每当cpu进行任务切换时,必须要考虑保存当前任务的执行状态和其他相关数据等,以便下次执行该任务时,能够正确恢复任务执行。程序的执行,也是一种任务执行。程序执行时,需要一个运行环境,包括指令集、数据集,和程序运行的状态信息等,我们称这个运行环境为"上下文"。上下文,在不同的地方表示不同的含义,大家要感性理解。
简单理解:上下文,就是任务当时运行的环境本身。不管是进程,还是线程,运行时都需要一个上下文环境来保证正确执行。cpu交替执行任务时,需要进行上下文切换。上下文切换,是指从当前执行任务切换到另一个任务执行时,为了确保下次能从正确的位置继续执行,在切换之前,需要保存上一个任务的状态。03什么是进程上面讲了一大堆的程序、程序执行等相关内容,其实都是在为“描述进程是什么”做铺垫。那么,进程是什么呢?进程,是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统进行资源分配的基本单位。简单来说:进程就是正在运行的程序的实例。简单来说:进程就是正在运行的程序的实例。简单来说:进程就是正在运行的程序的实例。
进程是一个运行中的程序,是程序的动态描述,是一个实体。所以,每一个进程都有它自己的地址空间,一般包括:文本区域、数据区域、堆栈区域。文本区域:存储处理器执行的机器语言代码;
数据区域:存储变量和进程执行期间使用的动态分配的内存;
堆栈区域:存储着活动过程调用的指令和本地变量。操作系统为了描述和控制进程的运行,通常将进程表示为一个结构体,称为:进程控制块,缩写:PCB(Process Control Block)。PCB是进程管理和控制的最重要的数据结构,每一个进程均有一个PCB。在创建进程时,建立PCB,伴随进程运行的全过程,直到进程撤消而撤消。PCB中,记录了操作系统所需的用于描述进程的当前情况以及控制进程运行的全部信息。PCB,一般包括:程序ID:也叫PID、进程句柄。它是唯一的,一个进程都必须对应一个PID,PID一般是整形数字。特征信息:一般分系统进程、用户进程、或者内核进程等。进程状态:运行、就绪、阻塞,表示进程的运行情况。优先级:表示获得CPU控制权的优先级大小。通信信息:进程之间的通信关系的反映,操作系统会提供通信信道。现场保护区:用于保护被阻塞的进程。资源需求:分配控制信息。进程实体信息:包含程序路径和名称等,指明进程数据在物理内存还是在交换分区中。其他信息:工作单位,工作区,文件信息等。最后需要注意的是,进程和程序是一对一的关系。注意区分我们这里说的程序,不是计算机上安装的应用程序。这是两个不同的概念,一个应用程序可以由很多程序组成。以windows下的chrome浏览器为例说明:chrome浏览器是一个应用程序,当我们打开chrome应用程序后,在任务管理器中的详细信息下,可以看到包含了很多的"chrome.exe",并且它们都有不同的PID,说明是多个进程。
所以,大家也完全可以将进程理解为一个正在操作系统运行的".exe"程序!
04什么是线程了解进程之后,我们就可以继续来了解线程了。在早期的操作系统中,并没有线程的概念。所以早期系统中,进程是拥有系统资源的最小单位,也是程序执行的最小单位。我们知道cpu采用的是时间片交替执行方式,以支持多任务同时进行。早期操作系统中,由于进程是拥有系统资源和程序执行的最小单位。每个进程各自拥有独立的一块内存,使得各个进程之间相互隔离。所以,在交替执行的过程中,cpu需要不停的切换进程,准备任务执行所需的上下文环境。进程切换的过程,会消耗大量系统资源,非常耗时。并且创建太多的进程,操作系统也是无法承受的。一个cpu ,多个进程 ,还要不停的切换,必定会导致系统卡顿,延迟飙升。这是我们无法忍受的~后来,随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的应用程序要求了。于是就出现了轻量级的,能够独立运行的基本单位 --线程。
Q:那么,什么是线程呢?A:线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。可以用一个公式,简单表示:线程 = 进程 - 共享资源
我们知道,进程的运行需要一个上下文环境。
在这个上下文环境中,会使用很多资源,如:寄存器、内存、虚拟地址空间、全局变量、文件描述符集合、堆栈等。
同样,线程的运行也有自己的上下文环境。
但是,线程的运行只需要拥有一些必不可少的资源即可。如,程序计数器、寄存器、栈等。
可以理解为:线程上下文,是进程上下文的子集。
因此,线程的切换比进程切换更快!每个进程至少需要一个线程,来完成对应的执行操作。因为,进程是资源分配的基本单位,线程是cpu调度执行的基本单位。即:cpu上真正运行的是线程。此时,这个线程被称为:主线程。当然,一个进程也可以拥有多个线程,每个线程执行不同的任务。当存在多个线程时,所有线程共享进程资源。
如果把一个进程比