day30 进程 同步 异步 阻塞 非阻塞 并发 并行创建进程守护进程 僵尸进程与孤儿进程互斥锁...

mac2022-06-30  31

操作系统发展史

1.第一带计算机 真空管和穿孔卡片 没有进程 没有操作系统 ​ 2.第二代计算机 7094 1401 晶体管 批处理系统 ​ 输入输出 以及计算设备 不能互联 需要人参与 一批一批的处理 开发效率慢 并且串行执行 ​ 3.第三代计算机 集成电路 与多道技术 ​ 多终端联机 spooling 同一台机器既能进行科学计算 又能做字符处理 通用计算机 ​ 多道技术 解决串行导致的效率低下问题 ​ 多用户终端 可以同时为多个用户提供服务 每个用户以为自己独享一台计算机 ​ 4.第四代 个人电脑 ​ 大规模使用了集成电路,大多都提供了GUI界面

多道技术

产生背景 ,所有程序串行 导致资源浪费

目的是让多个程序可以并发执行 , 同时处理多个任务

空间复用 指的是 同一时间 内存中加载多个不同程序数据, 每个进程间内存区域相互隔离,物理层面的隔离 时间复用 切换 + 保存 切换条件: 1.一个进程执行过程中遇到了IO操作 切换到其他进程 2.运行时间过长,会被操作系统强行剥夺执行权力 单纯的切换不够,必须在切换前保存当前的状态,以便于恢复执行

进程

一个正在被运行的程序就称之为进程,是程序具体执行过程,一种抽象概念

进程来自于操作系统

进程和程序的区别

程序就是一堆计算机可以识别文件,程序在没有被运行就是躺在硬盘上的一堆二进制

运行程序时,要从硬盘读取数据到内存中,CPU从内存读取指令并执行 ,

一旦运行就产生了进程

一个程序可以多次执行 产生多个进程,但是进程之间相互独立

当我们右键运行了一个py文件时 ,其实启动的是python解释器,你的py文件其实是当作参数传给了解释器

同步 异步 阻塞 非阻塞 并发 并行

同步 异步 指的是任务的提交方式
1.同步:任务提交之后 原地等待的任务的执行并拿到返回结果才走 期间不做任何事(程序层面的表现就是卡住了) 2.异步:任务提交之后 不再原地等待 而是继续执行下一行代码(结果是要的 但是是用过其他方式获取)
阻塞 非阻塞 指的是程序的运行状态
阻塞 : 程序遇到io操作是就进入了阻塞状态 ,程序无法继续执行其他代码 ​ 本地IO input print sleep read write ​ 网络IO recv send 非阻塞: 程序正常运行中 没有任何IO操作 就处于非阻塞状态 ,或者通过某种方式使程序即时遇到了也不会停在原地,还可以执行其他操作,以提高CPU的占用率
并发 并行 说的是 任务的处理方式
并发: 多个任务看起来同时在处理 ,本质上是切换执行 速度非常快 并行: 多个任务真正的同时执行 必须具备多核CPU 才可能并行

进程的三种状态

  

 

就绪态,运行态,和阻塞态

多道技术会在进程执行时间过长或遇到IO时自动切换其他进程,意味着IO操作与进程被剥夺CPU执行权都会造成进程无法继续执行

创建进程

创建进程就是在内存中重新开辟一块内存空间,将允许产生的代码丢进去,一个进程对应在内存就是一块独立的内存空间 进程与进程之间数据是隔离的 无法直接交互,但是可以通过某些技术实现间接交互 实例化Process,将要执行任务用target传入 from multiprocessing import Process import time def test(name): print('%s is running'%name) time.sleep(2) print('%s is over'%name) # windows创建进程会将代码以模块的方式 从上往下执行一遍 # linux会直接将代码完完整整的拷贝一份 # windows创建进程一定要在if __name__ == '__main__':代码块内创建 否则报错 if __name__ == '__main__': # 创建一个进程对象 p = Process(target=test,args=('lolo',)) # 告诉操作系统帮你创建进程 p.start() print('') 1 继承Process,并覆盖run方法, 将任务放入run方法中 from multiprocessing import Process import time class MyProcess(Process): def __init__(self,name): super().__init__() self.name = name def run(self): print('%s is running'%self.name) time.sleep(2) print('%s is over'%self.name) if __name__ == '__main__': p = MyProcess('coco') p.start() print('') 2 1.在windows下 开启子进程必须放到__main__下面,因为windows在开启子进程时会重新加载所有的代码造成递归创建进程 2.第二种方式中,必须将要执行的代码放到run方法中,子进程只会执行run方法其他的一概不管 进程间内存相互隔离

join函数

Process的对象具备一个join函数

用于提高子进程优先级 ,使得父进程等待子进程结束

from multiprocessing import Process import time def test(name,i): print('%s is running'%name) time.sleep(i) print('%s is over'%name) if __name__ == '__main__': p_list = [] for i in range(3): p = Process(target=test,args=('进程%s'%i,i)) p.start() p_list.append(p) for p in p_list: p.join() p1 = Process(target=test,args=('dodo',2)) p2 = Process(target=test,args=('lolo',1)) p1.start() p2.start() p1.join() View Code

进程间相互隔离

from multiprocessing import Process money = 100 def test(): global money money = 888 if __name__ == '__main__': p = Process(target=test) p.start() p.join() print(money) 验证

进程对象及其它方法

from multiprocessing import Process,current_process,active_children import os import time def test(name): print('%s is running'%name,current_process().pid) print('%s run'%name,os.getpid(),os.getppid()) time.sleep(1) print('%s is over'%name) if __name__ == '__main__': p = Process(target=test,args=('lolo',)) p.start() p.terminate() # 杀死当前进程 其实是告诉操作系统帮你杀死一个进程 print(p.is_alive()) # 判断进程是否存活 print('',os.getpid(), os.getppid()) View Code # p.join() # 等待子进程结束 # p.terminate() # 终止进程 # print(p.name) # 进程的名称 # print(p.is_alive()) #是否存活 # p.terminate() # 与start一样 都是给操作系统发送指令 所以会有延迟 # print(p.is_alive()) # print(p.pid) # print(p.exitcode) # 获取退出码

  

守护进程

进程:一个正在运行的程序。 主进程创建守护进程: 1.守护进程会在主进程代码执行结束后就终止, 2.守护进程内无法再开启子进程,否则抛出异常。 注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止。 from multiprocessing import Process import time def teat(name): print('%s 在'%name) time.sleep(1) print('%s 不在'%name) if __name__ == '__main__': p = Process(target=teat,args=('coco',)) p.daemon = True p.start() # p.daemon = True time.sleep(0.1) print('老板不在') View Code

僵尸进程与孤儿进程

孤儿进程 孤儿进程指的是开启子进程后,父进程先于子进程终止了,那这个子进程就称之为孤儿进程 孤儿进程是无害的,有其存在的必要性,在父进程结束后,其子进程会被操作系统接管。 僵尸进程 僵尸进程指的是,当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。如果父进程先退出 ,子进程被操作系统接管,子进程退出后操作系统会回收其占用的相关资源! 僵尸进程的危害: 由于子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 在Linux中,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用, 在python中,已经封装好了wait操作不需要我们自己清理。 但是系统所能使用的进程号是有限的,如果大量的产生[僵死进程],将因为没有可用的进程号而导致系统不能产生新的进程. 此为僵尸进程的危害,应当避免。

  

互斥锁

互相排斥的锁(如果这个资源已经被锁了,其他进程就无法使用了) 需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行。 使用场景: 并发将带来资源的竞争问题, 当多个进程同时要操作同一个资源时,将会导致数据错乱的问题。

 

解决方案1: ​ 加join, 例子: from multiprocessing import Process import time def task1(): print('你好,阿森。。。') time.sleep(3) print('吃饭') time.sleep(3) print('下雨') def task2(): print('你好,阿三。。。') time.sleep(3) print('吃面') time.sleep(3) print('下雪') def task3(): print('你好,阿四。。。') time.sleep(3) print('吃米') time.sleep(3) print('下冰雹') if __name__ == '__main__': p1 = Process(target=task1) p2 = Process(target=task2) p3 = Process(target=task3) p1.start() p1.join() p2.start() p2.join() p3.start() p3.join() ​ 弊端: 1.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了。 ​    2.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的。 解决方案2: ​ 就是给公共资源加 锁----互斥锁。 例子: from multiprocessing import Process,Lock import time,random def task1(lock): # 上锁 lock.acquire() #就等同于一个if判断 print('你好,阿森。。。') time.sleep(random.randint(0,3)) print('吃饭') time.sleep(random.randint(0, 3)) print('下雨') #解锁 lock.release() def task2(lock): lock.acquire() print('你好,阿三。。。') time.sleep(random.randint(0, 3)) print('吃面') time.sleep(random.randint(0, 3)) print('下雪') lock.release() def task3(lock): lock.acquire() print('你好,阿四。。。') time.sleep(random.randint(0, 3)) print('吃米') time.sleep(random.randint(0, 3)) print('下冰雹') lock.release() if __name__ == '__main__': lock=Lock() p1=Process(target=task1,args=(lock,)) p2=Process(target=task2,args=(lock,)) p3=Process(target=task3,args=(lock,)) p1.start() p2.start() p3.start() View Code # 注意1: 不要对同一把执行多出acquire 会锁死导致程序无法执行 一次acquire必须对应一次release from multiprocessing import Lock l=Lock() l.acquire() print('抢到了') l.release() l.acquire() print('接着抢') # 注意2:想要保住数据安全,必须保住所有进程使用同一把锁 锁和join的区别: 1.  join是固定了执行顺序,会造成父进程等待子进程完成后完成 ​    锁是公平竞争谁先抢到谁先执行,父进程可以做其他事情、 2.  join是把进程的任务全部串行 ​   锁可以锁任意代码 ,一行也可以 可以自己调整粒度 粒度: 粒度越大意味着锁住的代码越多 效率越低 粒度越小意味着锁住的代码越少 效率越高 MYSQL 中不同隔离级别 其实就是不同的粒度  

 小练习 -- 抢票

""" 过程: 1.查看余票, 2.有就买,无失败 os.getpid()获取当前进程id #文件db的内容为:{"count":1} #注意一定要用双引号,不然json无法识别 """ from multiprocessing import Process, Lock import json, random, time, os def check_ticket(): with open('ticket.json', 'rt', encoding='utf-8')as a: data = json.load(a) time.sleep(random.randint(0, 3)) print('%s正在查票,票还有%s' % (os.getpid(), data["count"])) def buy_ticket(): with open('ticket.json', 'rt', encoding='utf-8')as a: data = json.load(a) if data["count"] > 0: data["count"] -= 1 # 模拟延迟 time.sleep(random.randint(0, 3)) with open('ticket.json', 'wt', encoding='utf-8')as a: json.dump(data, a) print('%s恭喜你抢票成功' % os.getpid()) else: print('%s抢票失败,开个加速包试一试' % os.getpid()) def task(lock): check_ticket() lock.acquire() buy_ticket() lock.release() if __name__ == '__main__': lock = Lock() # 三个人抢票 for i in range(10): p = Process(target=task, args=(lock,)) p.start() 抢票

转载于:https://www.cnblogs.com/komorebi/p/11348565.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)