网络基础之 并发编程之进程,多路复用,multiprocess模块

并发
1. 背景知识
2. 什么是进程
3. 进程调度
4. 并发与并行
5 同步\异步\阻塞\非阻塞(重点)
6.multiprocess模块
7.僵尸进程与孤儿进程

1.背景知识

一操做系统的做用:
1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
2:管理、调度进程,而且将多个进程对硬件的竞争变得有序

二 多道技术:
1.产生背景:针对单核,实现并发
ps:如今的主机通常是多核,那么每一个核都会利用多道技术有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再从新调度,
会被调度到4个cpu中的任意一个,具体由操做系统调度算法决定。

2.空间上的复用:如内存中同时有多道程序

3.时间上的复用:复用一个cpu的时间片
强调:遇到io切,占用cpu时间过长也切,核心在于切以前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行


2. 什么是进程

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

进程的概念:
第一,进程是一个实体。每个进程都有它本身的地址空间,通常状况下,包括文本区域(text region)(python的文件)、数据区域(data region)(python文件中定义的一些变量数据)和堆栈(stack region)。
文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。

第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操做系统执行之),它才能成为一个活动的实体,咱们称其为进程。[3]
进程是操做系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态状况,描述系统内部各道程序的活动规律引进的一个概念,全部多道程序设计操做系统都创建在进程的基础上。

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

多个不一样的进程能够包含相同的程序:一个程序在不一样的数据集里就构成不一样的进程,能获得不一样的结果;可是执行过程当中,程序不能发生改变。

程序和进程的区别

程序是指令和数据的有序集合,其自己没有任何运行的含义,是一个静态的概念。
而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
程序能够做为一种软件资料长期存在,而进程是有必定生命期的。
程序是永久的,进程是暂时的。

3. 进程调度
1.先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于做业调度,也可用于进程调度。FCFS算法比较有利于长做业(进程),而不利于短做业(进程)
2.短做业(进程)优先调度算法(SJ/PF)是指对短做业或短进程优先调度的算法,该算法既可用于做业调度,也可用于进程调度。但其对长做业不利;不能保证紧迫性做业(进程)被及时处理;做业的长短只是被估算出来的
3.时间片轮转(Round Robin,RR)法的基本思路是让每一个进程在就绪队列中的等待时间与享受服务的时间成比例。在时间片轮转法中,须要将CPU的处理时间分红固定大小的时间片,例如,几十毫秒至几百毫秒
4.多级反馈队列调度算法,没必要事先知道各类进程所需的执行时间,并且还能够知足各类类型进程的须要,于是它是目前被公认的一种较好的进程调度算法。


4. 并发与并行
不管是并行仍是并发,在用户看来都是'同时'运行的,无论是进程仍是线程,都只是一个任务而已,真是干活的是cpu,cpu来作这些任务,而一个cpu同一时刻只能执行一个任务
并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就能够实现并发,(并行也属于并发)
并行:同时运行,只有具有多个cpu才能实现并行

多道技术概念回顾:内存中同时存入多道(多个)程序,cpu从一个进程快速切换到另一个,使每一个进程各自运行几十或几百毫秒,
这样,虽然在某一个瞬间,一个cpu只能执行一个任务,但在1秒内,cpu却能够运行多个进程,这就给人产生了并行的错觉,即伪并行,以此来区分多处理器操做系统的真正硬件并行(多个cpu共享同一个物理内存)


5.同步\异步\阻塞\非阻塞(重点)
1.进程状态介绍
(1)就绪(Ready)状态当进程已分配到除CPU之外的全部必要的资源,只要得到处理机即可当即执行,这时的进程状态称为就绪状态。
(2)执行/运行(Running)状态当进程已得到处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。
(3)阻塞(Blocked)状态正在执行的进程,因为等待某个事件发生而没法执行时,便放弃处理机而处于阻塞状态。引发进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能知足、等待信件(信号)等。
    事件请求:input、sleep、文件输入输出、recv、accept等
    事件发生:sleep、input等完成了
    时间片到了以后有回到就绪状态,这三个状态不断的在转换

2.同步异步

1.所谓同步就是一个任务的完成须要依赖另一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列
2.所谓异步是不须要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工做,依赖的任务也当即执行,只要本身完成了整个任务就算完成了。
至于被依赖的任务最终是否真正完成,依赖它的任务没法肯定,因此它是不可靠的任务序列。

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


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

同步阻塞形式:效率最低。拿上面的例子来讲,就是你专心排队,什么别的事都不作。

异步阻塞形式:若是在排队取餐的人采用的是异步的方式去等待消息被触发(通知),也就是领了一张小纸条,假如在这段时间里他不能作其它的事情,就在那坐着等着,不能玩游戏等,那么很显然,这我的被阻塞在了这个等待的操做上面;
异步操做是能够被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息通知时被阻塞。

同步非阻塞形式:其实是效率低下的。想象一下你一边打着电话一边还须要抬头看到底队伍排到你了没有,若是把打电话和观察排队的位置当作是程序的两个操做的话,
这个程序须要在这两种不一样的行为之间来回的切换,效率可想而知是低下的。

异步非阻塞形式:效率更高,由于打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不一样的操做中来回切换。

tips:不少人会把同步和阻塞混淆,是由于不少时候同步操做会以阻塞的形式表现出来,一样的,不少人也会把异步和非阻塞混淆,由于异步操做通常都不会在真正的IO操做处被阻塞。


6.multiprocess模块
1.process模块介绍
process模块是一个建立进程的模块,借助这个模块,就能够完成进程的建立。

主进程建立的子进程是异步执行的,那么咱们就验证一下,而且看一会儿进程和主进程(也就是父进程)的ID号(讲一下pid和ppid,使用pycharm举例),来看看是不是父子关系。
from multiprocessing import Process import time,os def func1(): time.sleep(2) print("我是func1") print("主进程>>",os.getpid()) def func2(): time.sleep(2) print("我是func2") print("子进程>>",os.getpid()) print("子进程的父进程>>", os.getppid()) if __name__ == "__main__": p = Process(target=func2) p.start() func1() print("主进程的父进程>>",os.getppid())

Process类中参数的介绍:
参数介绍:
1 group参数未使用,值始终为None
2 target表示调用对象,即子进程要执行的任务
3 args表示调用对象的位置参数元组,args=(1,2,'egon',)
4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
5 name为子进程的名称

给要执行的函数传参数:
from multiprocessing import Process
import time
def func(m,n):
    print(m)
    time.sleep(1)
    print(n)
if __name__ == '__main__':
    p1 = Process(target=func,args=(10,20))
    p1.start()

 

Process类中各方法的介绍:
1 p.start():启动进程,并调用该子进程中的p.run()
2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,咱们自定义类的类中必定要实现该方法
3 p.terminate():强制终止进程p,不会进行任何清理操做,若是p建立了子进程,该子进程就成了僵尸进程,使用该方法须要特别当心这种状况。若是p还保存了一个锁那么也将不会被释放,进而致使死锁
4 p.is_alive():若是p仍然运行,返回True
5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。
timeout是可选的超时时间,须要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

 Process类中自带封装的各属性的介绍
1 p.daemon:默认值为False,若是设为True,表明p为后台运行的守护进程,当p的父进程终止时,p也随之终止,而且设定为True后,p不能建立本身的新进程,必须在p.start()以前设置
2 p.name:进程的名称
3 p.pid:进程的pid
4 p.exitcode:进程在运行时为None、若是为–N,表示被信号N结束(了解便可)
5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络链接的底层进程间通讯提供安全性,这类链接只有在具备相同的身份验证键时才能成功(了解便可)

2.Process类的使用

进程的建立第二种方法(继承)
from multiprocessing import Process import time class myprocess(Process): def __init__(self,n): super().__init__() self.n = n def run(self): #想要定义功能,必须采用run的名字,由于target会调用名称为run的函数 time.sleep(2) print("我是run") if __name__ == '__main__': p1 = myprocess(10) p1.start()

进程之间的数据是隔离的:
验证明例:
from multiprocessing import Process import time,os num = 100 def func(): global num num -= 1 print("子程序pid:%s,子程序的父程序%s,num=%s"%(os.getpid(),os.getppid(),num)) lis = [] if __name__ == '__main__': for i in range(10): p = Process(target=func) p.start() lis.append(p) for el in lis: el.join() print("主程序pid:%s,num=%s"%(os.getpid(),num))

进程对象的其余方法一:terminate,is_alive

from multiprocessing import Process import time import random class Piao(Process): def __init__(self,name): super().__init__() self.name = name # def run(self): print('%s is 玩泥巴' %self.name) # s = input('???') #别忘了再pycharm下子进程中不能input输入,会报错EOFError: EOF when reading a line,由于子进程中没有像咱们主进程这样的在pycharm下的控制台能够输入东西的地方 time.sleep(2) print('%s is 玩泥巴结束' %self.name) if __name__ == '__main__': p1 = Piao("尼古拉斯") p1.start() time.sleep() p1.terminate()#关闭进程,不会当即关闭,有个等着操做系统去关闭这个进程的时间,因此is_alive马上查看的结果可能仍是存活,可是稍微等一会,就被关掉了 print(p1.is_alive()) #结果为True print('等会。。。。') time.sleep(1) print(p1.is_alive()) #结果为False

 

7.僵尸进程与孤儿进程(简单了解 一下就能够啦)  僵尸进程:一个进程使用fork建立子进程,若是子进程退出,而父进程并无调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。详解以下咱们知道在unix/linux中,正常状况下子进程是经过父进程建立的,子进程在建立新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远没法预测子进程到底何时结束,若是子进程一结束就马上回收其所有资源,那么在父进程内将没法获取子进程的状态信息。    孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工做。孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工做
相关文章
相关标签/搜索