zoukankan      html  css  js  c++  java
  • day030进程的两种创建方法,验证进程的空间隔离,join等待子进程

    本节内容:

    1.操作系统的简单介绍
    2.进程的两种创建方法
    3.进程之间是空间隔离的,

    参考文章:

    一、操作系统的简单介绍

    1、操作系统简单介绍

    操作系统就是一个协调、管理和控制计算机硬件资源和软件资源的控制程序。
    操作系统位于计算机硬件与应用软件之间,本质也是一个软件。
    操作系统由操作系统的内核(运行于内核态,管理硬件资源)以及系统调用
    (运行于用户态,为应用程序员写的应用程序提供系统调用接口)两部分组成,
    所以,单纯的说操作系统是运行于内核态的,是不准确的。

    2、细说的话,操作系统应该分成两部分功能:

    一:隐藏了丑陋的硬件调用接口(键盘、鼠标、音箱等等怎么实现的,就不需要你管了),
    为应用程序员提供调用硬件资源的更好,更简单,更清晰的模型(系统调用接口)。
    应用程序员有了这些接口后,就不用再考虑操作硬件的细节,专心开发自己的应用程序即可。
    
    例如:操作系统提供了文件这个抽象概念,对文件的操作就是对磁盘的操作,
    有了文件我们无需再去考虑关于磁盘的读写控制(比如控制磁盘转动,移动磁头读写数据等细节),
    
    二:将应用程序对硬件资源的竞态请求变得有序化
    
    例如:很多应用软件其实是共享一套计算机硬件,比方说有可能有三个应用程序同时需要申请打印机来输出内容,
    那么a程序竞争到了打印机资源就打印,然后可能是b竞争到打印机资源,也可能是c,这就导致了无序,
    打印机可能打印一段a的内容然后又去打印c...,操作系统的一个功能就是将这种无序变得有序。

    <details>
    <summary>操作系统详解</summary>

    #作用一:为应用程序提供如何使用硬件资源的抽象
    例如:操作系统提供了文件这个抽象概念,对文件的操作就是对磁盘的操作,有了文件我们无需再去考虑关于磁盘的读写控制
    
    注意:
        操作系统提供给应用程序的该抽象是简单,清晰,优雅的。为何要提供该抽象呢?
        硬件厂商需要为操作系统提供自己硬件的驱动程序(设备驱动,这也是为何我们要使用声卡,就必须安装声卡驱动。。。),厂商为了节省成本或者兼容旧的硬件,它们的驱动程序是复杂且丑陋的
        操作系统就是为了隐藏这些丑陋的信息,从而为用户提供更好的接口
        这样用户使用的shell,Gnome,KDE看到的是不同的界面,但其实都使用了同一套由linux系统提供的抽象接口
    
    
    #作用二:管理硬件资源
        现代的操作系统运行同时运行多道程序,操作系统的任务是在相互竞争的程序之间有序地控制对处理器、存储器以及其他I/O接口设备的分配。
    例如:
        同一台计算机上同时运行三个程序,它们三个想在同一时刻在同一台计算机上输出结果,那么开始的几行可能是程序1的输出,
        接着几行是程序2的输出,然后又是程序3的输出,最终将是一团糟(程序之间是一种互相竞争资源的过程)
    
        操作系统将打印机的结果送到磁盘的缓冲区,在一个程序完全结束后,才将暂存在磁盘上的文件送到打印机输出,
        同时其他的程序可以继续产生更多的输出结果(这些程序的输出没有真正的送到打印机),这样,操作系统就将由竞争产生的无序变得有序化。

    </details>

    3、多道程序设计技术(重点)

    所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。
    即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。
    当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。

    1.什么是io切

    即在执行input或者ouput的时候,cup会空闲,
    在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。
    
        多道程序设计技术不仅使CPU得到充分利用,同时改善I/O设备和内存的利用率,
    从而提高了整个系统的资源利用率和系统吞吐量(单位时间内处理作业(程序)的个数),最终提高了整个系统的效率。
    
    单处理机系统中多道程序运行时的特点:
        (1)多道:计算机内存中同时存放几道相互独立的程序;
        (2)宏观上并行:同时进入系统的几道程序都处于运行过程中,即它们先后开始了各自的运行,但都未运行完毕;
        (3)微观上串行:实际上,各道程序轮流地用CPU,并交替运行。

    2.空间和时间上的复用

    多道程序系统的出现,标志着操作系统渐趋成熟的阶段,先后出现了作业调度管理、处理机管理、存储器管理、外部设备管理、文件系统管理等功能。

        由于多个程序同时在计算机中运行,开始有了空间隔离的概念,只有内存空间的隔离,才能让数据更加安全、稳定。
        出了空间隔离之外,多道技术还第一次体现了时空复用的特点,遇到IO操作就切换程序,使得cpu的利用率提高了,计算机的工作效率也随之提高。

     空间上的复用:将内存分为几部分,每个部分放入一个程序,这样,同一时间内存中就有了多道程序。

     时间上的复用:当一个程序在等待I/O时,另一个程序可以使用cpu,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%

    二、什么是进程

    进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
    在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。
    程序是指令、数据及其组织形式的描述,进程是程序的实体。我们自己在python文件中写了一些代码,这叫做程序,运行这个python文件的时候,这叫做进程。

      狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
      广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

      举例: 比如py1文件中有个变量a=1,py2文件中有个变量a=2,他们两个会冲突吗?不会的,是不是,因为两个文件运行起来后是两个进程,操作系统让他们在内存上隔离开,对吧。

    <details>
    <summary>进程的概念</summary>

    第一,进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)(python的文件)、数据区域(data region)
    (python文件中定义的一些变量数据)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;
    堆栈区域存储着活动过程调用的指令和本地变量。
    
    第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。
    进程是操作系统中最基本、重要的概念。
    
    是多道程序系统出现后,为了刻画系统内部出现的动态情况,
    描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。

    </details>

    <details>
    <summary>进程的特征</summary>

    动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
    并发性:任何进程都可以同其他进程一起并发执行
    独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
    异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
    结构特征:进程由程序、数据和进程控制块三部分组成。
    多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

    </details>

    <details>
    <summary>进程与程序的区别</summary>

    程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
    而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
    程序可以作为一种软件资料长期存在,而进程是有一定生命期的。
    程序是永久的,进程是暂时的。
    举例:就像qq一样,qq是我们安装在自己电脑上的客户端程序,其实就是一堆的代码文件,我们不运行qq,那么他就是一堆代码程序,当我们运行qq的时候,这些代码运行起来,就成为一个进程了。

    </details>

    三、并发与并行

    通过进程之间的调度,也就是进程之间的切换,我们用户感知到的好像是两个视频文件同时在播放,
    或者音乐和游戏同时在进行,那就让我们来看一下什么叫做并发和并行
    
    无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,
    真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务

    1、并发

    是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)

    fe: 并发的示例说法

    你是一个cpu,你同时谈了三个女朋友,每一个都可以是一个恋爱任务,你被这三个任务共享要玩出并发恋爱的效果,
    应该是你先跟女友1去看电影,看了一会说:不好,我要拉肚子,然后跑去跟第二个女友吃饭,吃了一会说:那啥,我去趟洗手间,然后跑去跟女友3开了个房,
    然后在你的基友眼里,你就在和三个女友同时在一起玩。

    2、并行:

    并行:同时运行,只有具备多个cpu才能实现并行
    将多个cpu必须成高速公路上的多个车道,进程就好比每个车道上行驶的车辆,
    并行就是说,大家在自己的车道上行驶,会不影响,同时在开车。这就是并行
    单核下,可以利用多道技术,多个核,每个核也都可以利用多道技术(多道技术是针对单核而言的)
    
      有四个核,六个任务,这样同一时间有四个任务被执行,假设分别被分配给了cpu1,cpu2,cpu3,cpu4,
    
        一旦任务1遇到I/O就被迫中断执行,此时任务5就拿到cpu1的时间片去执行,这就是单核下的多道技术
    
        而一旦任务1的I/O结束了,操作系统会重新调用它(需知进程的调度、分配给哪个cpu运行,由操作系统说了算),可能被分配给四个cpu中的任意一个去执行
    
        所有现代计算机经常会在同一时间做很多件事,一个用户的PC(无论是单cpu还是多cpu),都可以同时运行多个任务(一个任务可以理解为一个进程)。
    
        启动一个进程来杀毒(360软件)
    
        启动一个进程来看电影(暴风影音)
    
        启动一个进程来聊天(腾讯QQ)
    
         所有的这些进程都需被管理,于是一个支持多进程的多道程序系统是至关重要的
    
        多道技术概念回顾:内存中同时存入多道(多个)程序,cpu从一个进程快速切换到另外一个,使每个进程各自运行几十或几百毫秒,这样,
        虽然在某一个瞬间,一个cpu只能执行一个任务,但在1秒内,cpu却可以运行多个进程,
        这就给人产生了并行的错觉,即伪并行,以此来区分多处理器操作系统的真正硬件并行(多个cpu共享同一个物理内存)

    四、同步异步阻塞非阻塞(重点)

    1.进程状态介绍

    在了解其他概念之前,我们首先要了解进程的几个状态。
    在程序运行的过程中,由于被操作系统的调度算法控制,程序会进入几个状态:就绪,运行和阻塞。
    
      (1)就绪(Ready)状态
    
        当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。
    
      (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
    
      (3)阻塞(Blocked)状态正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。
    
      事件请求:input、sleep、文件输入输出、recv、accept等
    
      事件发生:sleep、input等完成了
    
      时间片到了之后有回到就绪状态,这三个状态不断的在转换。

    2、同步异步

    所谓同步
    就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。
    要么成功都成功,失败都失败,两个任务的状态可以保持一致。
    其实就是一个程序结束才执行另外一个程序,串行的,不一定两个程序就有依赖关系。
    
    所谓异步
    是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,
    只要自己完成了整个任务就算完成了。
    至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。

    fe:实例说明

    同步:你跟你前面的点了一份猪脚饭,只有一个厨师,需要排你前面的人完成了,才到你,
    异步:取号排队,取了号,你可以在期间做其他事情,去喝个茶,打个游戏,逛个街再回来

    3、阻塞与非阻塞

    阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。
    也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的状态角度来说的

    fe:实例说明

    阻塞:在排队的时候,什么都没带,只能干等这排队,做不了其他事情
    非阻塞:在排队的时候,带了手机,可以边排队边打游戏

    4.同步/异步 与 阻塞和非阻塞

    1、同步阻塞形式
        效率最低。拿上面的例子来说,就是你专心排队,什么别的事都不做。
    
    2、异步阻塞形式
        如果在排队取餐的人采用的是异步的方式去等待消息被触发(通知),也就是领了一张小纸条,假如在这段时间里他不能做其它的事情,就在那坐着等着,不能玩游戏等,那么很显然,这个人被阻塞在了这个等待的操作上面;
    
        异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞。
    3、同步非阻塞形式
        实际上是效率低下的。
    
        想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的。
    
    4、异步非阻塞形式
        效率更高,
    
        因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换。
    
        比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉点餐员说,排到我这个号码的时候麻烦到外面通知我一下,那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了。
    
        很多人会把同步和阻塞混淆,是因为很多时候同步操作会以阻塞的形式表现出来,同样的,很多人也会把异步和非阻塞混淆,因为异步操作一般都不会在真正的IO操作处被阻塞。

    五、进程的创建、结束与并发的实现(了解)

    1.进程的创建

    但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,
    一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在。
    
    而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式创建新的进程
    
    1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,
    运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
    
    2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)
    
    3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)
    
    4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)
    无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:
    
    1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)
    
    2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。
    
    
    关于创建的子进程,UNIX和windows
    
    1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),
    任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。
    
    2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。
    但是对于windows系统来说,从一开始父进程与子进程的地址空间就是不同的。

    2、进程的结束

    1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)
    
    2. 出错退出(自愿,python a.py中a.py不存在)
    
    3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)
    
    4. 被其他进程杀死(非自愿,如kill -9)

    3.进程并发的实现(了解)

    进程并发的实现在于,硬件中断一个正在运行的进程,把此时进程运行的所有状态保存下来,
    为此,操作系统维护一张表格,即进程表(process table),每个进程占用一个进程表项(这些表项也称为进程控制块)

    该表存放了进程状态的重要信息:程序计数器、堆栈指针、内存分配状况、所有打开文件的状态、帐号和调度信息,以及其他在进程由运行态转为就绪态或阻塞态时,必须保存的信息,从而保证该进程在再次启动时,就像从未被中断过一样。

    fe1:进程创建示例

    from multiprocessing import Process
    # 方式1
    import time
    
    def func1():
        time.sleep(3)
        print(111111)
    
    
    def func2():
        time.sleep(2)
        print(22222)
        print('子进程的pid',os.getpid()) #查看当前进程的id,这个不是端口号
        print('子进程的父进程>>>',os.getppid())  #查看父进程的id
    
    if __name__ == '__main__':
    
        print('主进程的pid',os.getpid())
        print('当前主进程的父进程>>>',os.getppid())
    
        p1 = Process(target=func1)
        p1.start()
        p2 = Process(target=func2)
        p2.start()  #告诉操作系统,我这边准备好了,你帮我创建并执行这个进程
    
        p1.join() #等待p1子进程执行完,主进程从这里才继续执行
        p2.join()
        # time.sleep(2)
        print('主进程')

    fe2:进程空间隔离示例

    from multiprocessing import Process
    
    num = 20
    
    def func():
        global num
        num = 10                        # 这里修改不会影响到主进程的num,体现了相互隔离
        print('子进程的num>>>>',num)    # 这里的num是在子进程有自己的内存空间,跟主进程的空间隔离了
    
    if __name__ == '__main__':
    
        p = Process(target=func,)
        p.start()
        p.join()
        print('主进程num:',num)

    六、进程对象的其他方法一:terminate, is_alive

    terminate()# 关闭进程,不会立即关闭,有个等着操作系统去关闭这个进程的时间,所以is_alive立刻查看的结果可能还是存活,但是稍微等一会,就被关掉了
    is_alive() # 判断进程是否还在存活,返回结果为:True或False

    fe: terminate() is_alive()

    from multiprocessing import Process
    import time
    import random
    
    class Piao(Process):
        def __init__(self,name):
            self.name=name
            super().__init__()
    
        def run(self):
            print('%s is 修飞机' %self.name)
            time.sleep(2)
            # s = input('???') #别忘了再pycharm下子进程中不能input输入,会报错EOFError: EOF when reading a line,因为子进程中没有像我们主进程这样的在pycharm下的控制台可以输入东西的地方
            print('%s is 修飞机结束' %self.name)
    
    if __name__ == '__main__':
        p1=Piao('太白')
        p1.start()
    
        p1.terminate()#关闭进程,不会立即关闭,有个等着操作系统去关闭这个进程的时间,所以is_alive立刻查看的结果可能还是存活,但是稍微等一会,就被关掉了
        print(p1.is_alive()) #结果为True
        print('等会。。。。')
        time.sleep(1)
        print(p1.is_alive()) #结果为False

    fe:pip name

    from multiprocessing import Process
    import time
    import random
    import os
    class Piao(Process):
        def __init__(self):
            # self.name=name
            # super().__init__() #Process的__init__方法会执行self.name=Piao-1,
            #                    #所以加到这里,会覆盖我们的self.name=name
    
            #为我们开启的进程设置名字的做法
            super().__init__()
            # self.name=name
    
        def run(self):
            # print('子进程id',os.getpid())
    
            print('%s is piaoing' %self.name)   # 进程的名字
            time.sleep(random.randrange(1,3))
            print('%s is piao end' %self.name)
    if __name__ == '__main__':
    
        p=Piao()
        p.start()
        print('开始')
        print(p.pid) #查看pid
        print(p.name) #查看pid
        print(os.getpid())
  • 相关阅读:
    退出程序
    筛选datatable
    1-2 开发环境搭建-Windows平台
    5-1 安全发布对象-发布与逸出
    4-4 线程安全性-可见性
    4-3 线程安全性-原子性-synchronized
    4-2 线程安全性-原子性-atomic-2
    4-1 线程安全性-原子性-atomic-1
    Spring
    Spring
  • 原文地址:https://www.cnblogs.com/yipianshuying/p/10027992.html
Copyright © 2011-2022 走看看