zoukankan      html  css  js  c++  java
  • 多进程,理论部分

    什么是进程?

    正在进行的一个过程或者说一个任务,而负责执行任务的是CPU

    进程与程序的区别

    程序只是一堆代码而已,而进程是程序的运行过程

    同一个程序执行两次,是开启两个不同的进程,比如:同一个视频播放器,开启两次分别播放不同的电影

    并发与并行

    无论是并发还是并行,在用户看来都是“同时”运行,不管是进程还是线程,都只是一个任务而已,真正干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务

    并发:是伪并行,即看起来是同时运行。cpu执行一会任务A,再去执行任务B,再去执行任务C,保证每个任务都在执行中。 单个CPU+多道技术,实现多个进程的并发执行

    并行:同时运行多个任务,只有具备多个CPU才能实现并行,并行也属于并发

    单核下,利用多道技术实现并发;多核,也可以利用多道技术(多道技术是针对单核而言的)

    多道技术:内存中同时存入多个程序,cpu从一个进程快速切换到另外一个进程,使每个进程各自运行几十或者几百毫秒,这样,虽然在某一个瞬间,一个cpu只能执行一个任务,但在1秒内,cpu却可以运行多个进程,这就给人产生了并行的错觉,即伪并行

                      多个cpu共享同一个物理内存

          进程的调度,分配给哪个cpu执行,由操作系统决定

            

    同步异步and阻塞非阻塞

    同步:发出一个功能调用时,在没有得到结果之前,该调用就不会返回。绝大多数函数都是同步调用。

      例如:multiprocessing.Pool下的apply,发起同步调用后,就在原地等待任务结束,根本不考虑任务是在计算还是在io阻塞,总之就是等待任务结束

    异步:发出一个异步功能调用,调用者不能立即得到结果,当异步功能完成后,通过状态,通知或者回调来通知调用者。

      如果异步功能用状态来通知,那么调用者就需要每隔一段时间检查一次,效率特别低

      使用通知的方法,效率则很高,因为异步功能几乎不需要做额外的操作

      回调函数,和通知的方法,差不多

      例如:multiprocessing.Pool().apply_async(),发起异步调用后,并不会等待任务结束才返回,相反,会立即获取一个临时结果(并不是最终的结果,可能是封装好的一个对象)

    阻塞:阻塞调用是指,调用结果返回之前,当前线程会被挂起(如遇到io操作),函数只有在得到结果之后才会将阻塞的线程激活

      有人也许会把阻塞调用和同步调用等同起来,实际上是不同的。对于异步调用来说,很多时候当前线程还是激活的,只是在逻辑上当前函数没有返回而已

      例如:同步调用:apply一个累计1亿次的任务,该调用会一直等待,直到任务返回结果为止,但并未阻塞(即便被抢走cpu的执行权限,也是处于就绪态)

         阻塞调用:当socket工作在阻塞模式的时候,如果没有数据的情况下调用recv函数,则当前线程会被挂起,直到有数据为止

    非阻塞:与阻塞的概念相对应,指在不能立即得到结果之前也会立刻返回,同时该函数不会阻塞当前线程

    小结:阻塞与非阻塞针对的是线程或者进程,阻塞是当请求不能满足的时候就将进程挂起,而非阻塞则不会阻塞当前进程

         同步与异步,针对的是函数/任务的调用方式,同步就是当一个进程发起一个函数/任务调用时,一直等到函数/任务完成,而进程继续处于激活状态;而异步情况下是当一个进程发起一个函数/任务调用的时候,不会等函数返回,而是继续往下执行,函数通过状态,通知,事件等方式通知进程任务完成。

    进程的创建

    1.系统初始化(查看进程,linux中使用ps命令,windows中使用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程)

    2.一个进程在运行过程中开启子进程

    3.用户的交互式请求,而创建一个新进程(打开播放器)

    4.一个批处理作业的初始化(只在大型机的批处理系统中应用)

    无论是哪一种,新进程的创建都是由一个已经存在的进行执行了一个用于创建进程的系统调用而创建的:

    1.在UNIX中该系统调用是fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像,同样的环境字符和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)

    2.在windows中该系统调用是CreateProcess,CreatProcess既处理进程的创建,也负责把正确的程序装入新进程

    关于创建的子进程,UNIX和Windows:

    1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程在其地址空间中的修改都不会影响另外一个进程。

    2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于Windows系统来说,从一开始父进程与子进程的地址空间就是不同的。 

    进程的终止

    1.正常退出,自愿,如Linux中使用exit,点击交互界面的叉号

    2.出错退出,自愿,python a.py,a.py不存在

    3.严重错误,非自愿,执行非法指令,如 引用不存在的变量,可以被异常捕捉,try...except...

    4.被其他进程杀死,非自愿,如kill -9

    进程的层次结构

    无论是UNIX还是Windows,进程只有一个父进程,不同的是:

    1.在UNIX中所有的进程都是以init进程为根,组成树形结果。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相似的进程组中的所有成员。

    2.在Windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了

    进程的状态

    tail -f access.log | grep "404"

    执行程序tail,开启一个子进程,执行程序grep,再开启另外一个子进程,两个进程之间基于管道"|"通信,将tail的结果作为grep的输入。

    进程grep 在等待输入时的状态称为阻塞态,此时grep命令都无法运行

    其实在两种情况下,会导致一个进程在逻辑上不能运行,

    1.进程挂起是自身原因,遇到IO阻塞,便要让出CPU让其他程序去执行,这样保证CPU一直在工作

    2.与进程无关,是操作系统层面,因为一个进程占用时间过长,或者优先级等原因,而调用其他的进程去使用CPU

    进程有三种状态:

        

      

    进程并发的实现

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

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

  • 相关阅读:
    Redis 设计与实现(第三章) -- 链表adlist
    Redis 设计与实现(第二章) -- SDS
    MySQL索引背后的数据结构及算法原理(转)
    MySQL索引原理及慢查询优化(转)
    MySQL常见的一些面试题(未完待续)
    js 获取前天、昨天、今天、明天、后天的时间
    linux 下nohup 使用
    java split 分割字符串用法
    Python 获取URL访问的HEAD头信息
    MySQL日期数据类型、时间类型使用总结
  • 原文地址:https://www.cnblogs.com/yizhixiaowenzi/p/12260541.html
Copyright © 2011-2022 走看看