进程
- 1.背景知识 -- 操作系统
- 2.什么是进程
- 3.并发与并行
- 4.同步\异步\阻塞\非阻塞
- 5.multprocess模块
1.背景知识 -- 操作系统 (ps:相关书籍,现代操作系统、操作系统原理)
(1)什么是操作系统
操作系统位于计算机硬件与应用软件之间,本质也是一个软件。操作系统由操作系统的内核(运行于内核态,管理硬件资源以及系统调用(运行于用户态,为应用程序员写的应用程序提供系统调用接口)两部分组成.
#一:隐藏了丑陋的硬件调用接口(键盘、鼠标、音箱等等怎么实现的,就不需要你管了),为应用程序员提供调用硬件资源的更好,更简单,更清晰的模型(系统调用接口)。应用程序员有了这些接口后,就不用再考虑操作硬件的细节,专心开发自己的应用程序即可。 例如:操作系统提供了文件这个抽象概念,对文件的操作就是对磁盘的操作,有了文件我们无需再去考虑关于磁盘的读写控制(比如控制磁盘转动,移动磁头读写数据等细节), #二:将应用程序对硬件资源的竞态请求变得有序化 例如:很多应用软件其实是共享一套计算机硬件,比方说有可能有三个应用程序同时需要申请打印机来输出内容,那么a程序竞争到了打印机资源就打印,然后可能是b竞争到打印机资源,也可能是c,这就导致了无序,打印机可能打印一段a的内容然后又去打印c...,操作系统的一个功能就是将这种无序变得有序。
#作用一:为应用程序提供如何使用硬件资源的抽象 例如:操作系统提供了文件这个抽象概念,对文件的操作就是对磁盘的操作,有了文件我们无需再去考虑关于磁盘的读写控制 注意: 操作系统提供给应用程序的该抽象是简单,清晰,优雅的。为何要提供该抽象呢? 硬件厂商需要为操作系统提供自己硬件的驱动程序(设备驱动,这也是为何我们要使用声卡,就必须安装声卡驱动。。。),厂商为了节省成本或者兼容旧的硬件,它们的驱动程序是复杂且丑陋的 操作系统就是为了隐藏这些丑陋的信息,从而为用户提供更好的接口 这样用户使用的shell,Gnome,KDE看到的是不同的界面,但其实都使用了同一套由linux系统提供的抽象接口 #作用二:管理硬件资源 现代的操作系统运行同时运行多道程序,操作系统的任务是在相互竞争的程序之间有序地控制对处理器、存储器以及其他I/O接口设备的分配。 例如: 同一台计算机上同时运行三个程序,它们三个想在同一时刻在同一台计算机上输出结果,那么开始的几行可能是程序1的输出,接着几行是程序2的输出,然后又是程序3的输出,最终将是一团糟(程序之间是一种互相竞争资源的过程) 操作系统将打印机的结果送到磁盘的缓冲区,在一个程序完全结束后,才将暂存在磁盘上的文件送到打印机输出,同时其他的程序可以继续产生更多的输出结果(这些程序的输出没有真正的送到打印机),这样,操作系统就将由竞争产生的无序变得有序化。 详解
(2)操作系统的发展史简介
第一代(1940~1955)手工操作---- 穿孔卡片
所有的程序设计是用纯粹的机器语言编写的,甚至更糟糕,需要通过成千上万根电缆接到插件板上连成电路来控制机器的基本功能.
特点:
手工操作特点:
- 用户独占全机。不会出现因资源已被其他用户占用而等待的现象,但资源的利用率低。
- CPU 等待手工操作。CPU的利用不充分。
- 没有操作系统的概念。
- 所有的程序设计都是直接操控硬件。
第二代(1955~1965) 磁带存储---批处理系统
摆脱人的手工操作,实现作业的自动过渡。这样就出现了成批处理。
- 有了操作系统的概念
- 有了程序设计语言:FORTRAN语言或汇编语言
1.联机批处理系统
首先出现的是联机批处理系统,即作业的输入/输出由CPU来处理
主机与输入机之间增加一个存储设备——磁带,在运行于主机上的监督程序的自动控制下,计算机可自动完成:成批处理数据
但是,在作业输入和结果输出时,主机的高速CPU仍处于空闲状态,等待慢速的输入/输出设备完成工作: 主机处于“忙等”状态。(忙等状态就是说CPU等着输出完成之后再去从输入机上读指令来执行,造成了CPU的浪费)
2.脱机批处理系统
为克服与缓解:高速主机与慢速外设(输入输出设备)的矛盾,提高CPU的利用率,又引入了脱机批处理系统,即输入/输出(input\output,简称I\O操作)脱离主机控制。
卫星机:一台不与主机直接相连而专门用于与输入/输出设备打交道的。 其功能是: (1)从输入机上读取用户作业并放到输入磁带上。 (2)从输出磁带上读取执行结果并传给输出机。 这样,主机不是直接与慢速的输入/输出设备打交道,而是与速度相对较快的磁带机发生关系,有效缓解了主机与设备的矛盾。主机与卫星机可并行工作,二者分工明确,可以充分发挥主机的高速计算能力。 不足:但目前为止,所有的程序都还是串行执行的,也就是一个程序结束才执行下一个程序,每次主机内存中仅存放一道作业,每当主机中这个运行期间的作业或者说程序发出输入/输出(I/O)请求后,CPU要去高速磁带里读数据,计算结果要往高速磁带里面写数据,那么高速的CPU便处于等待低速的I/O完成状态,CPU并没有完全的运算起来,也可以理解为我要等着你输入或者等着你输出,致使CPU空闲。注意:之前系统的缺点说的是等待用户将程序全部输入进去,等待程序运行结束后输出最终结果的操作。现在说的是程序运行期间发生的输入\输出操作,也就是去高速磁带里面去读取程序数据,然后将输出数据写到高速磁带中,也是耗时的,cpu这段时间内的利用率也是很低的,为改善CPU的利用率,又引入了多道程序系统。
1.多道程序设计技术
所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。
在A程序计算时,I/O空闲, A程序I/O操作时,CPU空闲(B程序也是同样);必须A工作完成后,B才能进入内存中开始工作,两者是串行的,全部完成共需时间=T1+T2。
将A、B两道程序同时存放在内存中,它们在系统的控制下,可相互穿插、交替地在CPU上运行:当A程序因请求I/O操作而放弃CPU时,B程序就可占用CPU运行,这样 CPU不再空闲,而正进行A I/O操作的I/O设备也不空闲,显然,CPU和I/O设备都处于“忙”状态,大大提高了资源的利用率,从而也提高了系统的效率,A、B全部完成所需时间<<T1+T2。
空间上的复用:将内存分为几部分,每个部分放入一个程序,这样,同一时间内存中就有了多道程序。
时间上的复用:当一个程序在等待I/O时,另一个程序可以使用cpu,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%
2.多道批处理系统
20世纪60年代中期,在前述的批处理系统中,引入多道程序设计技术后形成多道批处理系统(简称:批处理系统)。 它有两个特点: (1)多道:系统内可同时容纳多个作业。这些作业放在外存中,组成一个后备队列,系统按一定的调度原则每次从后备作业队列中选取一个或多个作业进入内存运行,运行作业结束、退出运行和后备作业进入运行均由系统自动实现,从而在系统中形成一个自动转接的、连续的作业流。 (2)成批:在系统运行过程中,不允许用户与其作业发生交互作用,即:作业一旦进入系统,用户就不能直接干预其作业的运行。 批处理系统的追求目标:提高系统资源利用率和系统吞吐量,以及作业流程的自动化。 批处理系统的一个重要缺点:不提供人机交互能力,给用户使用计算机带来不便。 虽然用户独占全机资源,并且直接控制程序的运行,可以随时了解程序运行情况。但这种工作方式因独占全机造成资源效率极低。 一种新的追求目标:既能保证计算机效率,又能方便用户使用计算机。 20世纪60年代中期,计算机技术和软件技术的发展使这种追求成为可能。 但是 有两个缺点,举例: 1、时间复用上的缺点:程序员A的程序运行10分钟就能够运行结束,程序员B的程序需要运行24小时,如何程序员B的程序先运行,并且程序员B的程序没有任何I\O操作,那么程序员A需要等待24小时之后才能执行,那么这就不太合理了。 2、空间复用上的缺点:首先丧失的是安全性,比如你的qq程序可以访问操作系统的内存,这意味着你的qq可以拿到操作系统的所有权限。其次丧失的是稳定性,某个程序崩溃时有可能把别的程序的内存也给回收了,比方说把操作系统的内存给回收了,则操作系统崩溃。 为了解决空间复用上的问题:程序之间的内存必须分割,由操作系统控制。如果内存彼此不分割,则一个程序可以访问另外一个程序的内存。 为了解决时间出现了分时系统
2.分时系统
分时技术:把处理机的运行时间分成很短的时间片,按时间片轮流把处理机分配给各联机作业使用。
若某个作业在分配给它的时间片内不能完成其计算,则该作业暂时中断,把处理机让给另一作业使用,等待下一轮时再继续其运行。由于计算机速度很快,作业运行轮转得很快,给每个用户的印象是,好象他独占了一台计算机。而每个用户可以通过自己的终端向系统发出各种操作控制命令,在充分的人机交互情况下,完成作业的运行。
具有上述特征的计算机系统称为分时系统,它允许多个用户同时联机使用计算机。
特点:
(1)多路性。若干个用户同时使用一台计算机。微观上看是各用户轮流使用计算机;宏观上看是各用户并行工作。
(2)交互性。用户可根据系统对请求的响应结果,进一步向系统提出新的请求。这种能使用户与系统进行人机对话的工作方式,明显地有别于批处理系统,因而,分时系统又被称为交互式系统。
(3)独立性。用户之间可以相互独立操作,互不干扰。系统保证各用户程序运行的完整性,不会发生相互混淆或破坏现象。
(4)及时性。系统可对用户的输入及时作出响应。分时系统性能的主要指标之一是响应时间,它是指:从终端发出命令到系统予以应答所需的时间。
分时系统的主要目标:对用户响应的及时性,即不至于用户等待每一个命令的处理时间过长。
分时系统可以同时接纳数十个甚至上百个用户,由于内存空间有限,往往采用对换(又称交换)方式的存储方法。即将未“轮到”的作业放入磁盘,一旦“轮到”,再将其调入内存;而时间片用完后,又将作业存回磁盘(俗称“滚进”、“滚出“法),使同一存储区域轮流为多个用户服务。
多用户分时系统是当今计算机操作系统中最普遍使用的一类操作系统。
注意:分时系统的分时间片工作,在没有遇到IO操作的时候就用完了自己的时间片被切走了,这样的切换工作其实并没有提高cpu的效率,反而使得计算机的效率降低了。为什么下降了呢?因为CPU需要切换,并且记录每次切换程序执行到了哪里,以便下次再切换回来的时候能够继续之前的程序,虽然我们牺牲了一点效率,但是却实现了多个程序共同执行的效果,这样你就可以在计算机上一边听音乐一边聊qq了。
背景小结:
#一 操作系统的作用: 1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口 2:管理、调度进程,并且将多个进程对硬件的竞争变得有序 #二 多道技术: 1.产生背景:针对单核,实现并发 ps: 现在的主机一般是多核,那么每个核都会利用多道技术 有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个 cpu中的任意一个,具体由操作系统调度算法决定。 2.空间上的复用:如内存中同时有多道程序 3.时间上的复用:复用一个cpu的时间片 强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样 才能保证下次切换回来时,能基于上次切走的位置继续运行
2.什么是进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。我们自己在python文件中写了一些代码,这叫做程序,运行这个python文件的时候,这叫做进程。
第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)(python的文件)、数据区域(data region)(python文件中定义的一些变量数据)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。 第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。[3] 进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。 进程的概念
动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
并发性:任何进程都可以同其他进程一起并发执行
独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
结构特征:进程由程序、数据和进程控制块三部分组成。
多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
程序可以作为一种软件资料长期存在,而进程是有一定生命期的。
程序是永久的,进程是暂时的。
举例:就像qq一样,qq是我们安装在自己电脑上的客户端程序,其实就是一堆的代码文件,我们不运行qq,那么他就是一堆代码程序,当我们运行qq的时候,这些代码运行起来,就成为一个进程了。
注意:同一个程序执行两次,就会在操作系统中出现两个进程,所以我们可以同时运行一个软件,分别做不同的事情也不会混乱
3.并发与并行
无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务
并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
并发会进行两项工作:
- 进程之间的切换
- 保护现场,保留你进程执行时的状态
并行:即并行:同时运行,只有具备多个cpu才能实现并行
4.同步\异步\阻塞\非阻塞
(1)进程状态介绍
在了解其他概念之前,我们首先要了解进程的几个状态。在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。 (1)就绪(Ready)状态 当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。 (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。 (3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。 事件请求:input、sleep、文件输入输出、recv、accept等 事件发生:sleep、input等完成了 时间片到了之后有回到就绪状态,这三个状态不断的在转换。
(2)同步&异步
所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。其实就是一个程序结束才执行另外一个程序,串行的,不一定两个程序就有依赖关系。
所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。
(3)阻塞&非阻塞
阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的
(4)同步/异步 与 阻塞/非阻塞
同步阻塞
异步阻塞
同步非阻塞
异步非阻塞
5.multprocess模块
(1)process模块介绍
process模块是一个创建进程的模块,借助这个模块可以完成进程的创建
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动) 强调: 1. 需要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
import os import time from multiprocessing import Process def func1(): print("子进程的",os.getpid()) print("子进程的父进程",os.getppid()) print (11111) time.sleep(5) if __name__ == "__main__": print("准备进行其他程序了") #当开始运行这个py文件,运行这个文件的程序,那么就产生了进程,这个进程我们称之为主进程 # print("子进程的",os.getpid()) # print("子进程的父进程",os.getppid()) p1 = Process(target=func1,) #将函数注册到一个进程中,p1是一个对象,此时还没有启动进程,只是创建了一个进程对象并且func是不加括号,而且, p1.start() #告诉操作系统,开启一个进程,func这个函数就会被新开的进程执行,而这个进程是主进程运行过程中创建出来的 #所以称这个新创建的进程是主进程的子进程,同样主进程又可称为这个新进程的父进程 #而这个子进程中执行的程序,相当于将这个py文件copy到一个你看不到的Python文件中去执行,就相当于当前这个文件,被另外一个py文件import过去并执行了 ##start并不是直接就去执行了,我们知道进程有三个状态,进程会进入进程的三个状态,就绪,(被调度,也就是时间片切换到它的时候)执行,阻塞,并且在这个三个状态之间不断的转换,等待cpu执行时间片到了。 print("到这里结束了") #这是主进程的程序,上面开启的子进程的程序是和主进程的程序同时运行的,我们称为异步
import os import time from multiprocessing import Process def func1(pycharm_id): print('子进程',os.getpid()) print('子进程的父进程',os.getppid()) print('子进程的爷爷进程的ID(pycharm)',pycharm_id) print(123) time.sleep(10) if __name__ == '__main__': pycharm_id = os.getppid() # # print('主进程的进程ID号>>>',os.getpid()) # #创建一个进程,target:我新创建的这个进程要去执行func1这个函数 p1 = Process(target=func1,args=(pycharm_id,)) #启动进程 p1.start() func1(pycharm_id) print('到这里结束了')