知识点一:守护进程
守护进程:p1.daemon=True
守护进程其实就是一个“子进程“,守护=》伴随
守护进程会伴随主进程的代码运行完毕后而死掉
进程:当父进程需要将一个任务并发出去执行,需要将该任务放到以个子进程里
守护:当该子进程内的代码在父进程代码运行完毕后就没有存在的意义了,就应该
将该子进程设置为守护进程,会在父进程代码结束后死掉
from multiprocessing import Process import time def foo(): print(123) time.sleep(1) print("end123") def bar(): print(456) time.sleep(3) print("end456") if __name__ == '__main__': p1=Process(target=foo) p2=Process(target=bar) # 将子进程p1设置为守护进程, # 所以p1会在print("main-------")打印完成后死掉,所以p1进程不会打印 p1.daemon=True p1.start() p2.start() # time.sleep(1) print("main-------")
主进程代码运行完,但是主进程不会死,还要回收子进程的僵尸进程,
所有守护进程只是守护主进程代码运行完就会死掉
p.daemon=True #守护进程要放在进程start之前
p.start()
print('主')
(1):正常情况子进程p不会打印,而会直接打印‘主’
(2):个别请况电脑速度快的时候,子类p里面的代码可能会运行(可能不是全部),然后等
主进程打印输出后,p会死掉(代码自上而下运行,操作系统产生并造出子类的速度快的前提下)
知识点二:进程的互斥锁
互斥锁:就是将要执行任务的部门代码(只涉及到修改共享数据的代码)变成串行
第一步:导入multiprocessing方法下面的Lock类
第二步:在if __name__ == '__main__':方法下面调用Lock类mutex=Lock(),拿到一个对象
第三步:在子类中需要共享的数据前后加入 加锁:mutex.acquire()——》需要共享修改数据的代码体《解锁:——mutex.release()
实验:实现简单的抢票功能
分析:1)查看变为并发(实现大家查询到的车票信息是一致的)
2)购买变为串行(因为购买涉及到了修改数据信息,所以一定要遵循先到先得)
(理解为用锁来限制,同一时间只能让一个人拿着锁去改数据,先抢到锁的人
就有优先购买的权限)
join:是将子类里面的所有代码都整体串行(就会将查询、购买2部分全部都变为串行,延迟更高)
互斥锁:可以挑选一段代码(修改数据即买票的那部分)单独抽出来加锁
#模拟抢票软件的原理:
from multiprocessing import Lock,Process import json,os,time,random def check(): #查票功能实现并行访问 time.sleep(1) with open('db.txt','rt',encoding='utf-8') as f: dic=json.load(f) print('%s 查看余票数为 %s'%(os.getpid(),dic['count'])) def get(): #购票因为牵涉到对后台数据的修改,所以加互斥锁目的是逐一进行访问修改,以免数据错乱 with open('db.txt', 'rt',encoding='utf-8') as f: dic = json.load(f) time.sleep(2) if dic['count'] >0: #有票 dic['count']-=1 time.sleep(random.randint(1, 3)) #在购票时,模拟网络延迟... with open('db.txt', 'wt',encoding='utf-8') as f: json.dump(dic,f) print('%s 购票成功'%os.getpid()) else: print('%s 没有余票'%os.getpid()) def task(mutex): #查看(并行访问) check() #抢票(加入互斥锁,实现串行访问,先到先得原则) mutex.acquire() get() mutex.release() #第一个购买完成后,解锁,后续进入继续购买 if __name__ == '__main__': mutex=Lock() #调用Lock类拿到一个对象 for i in range(10): p=Process(target=task,args=(mutex,)) p.start()
知识点三:进程间的通信
需求的演变思路:就是为了用一块儿共享的内存==》实现进程间的共享
必须有2个特点:
1.一定是内存空间
2.能够自动帮忙处理锁的问题
IPC机制:
PIPE:管道
Queue:PIPE+锁(队列)
注意:
1.队列占用的是内存空间
2.不应该往队列中放大数据,应该只存放数据量较小的精简的内容
重点讲队列:Queue 同样也是在multiprocessing方法里面导入Queue模块: from multiprocessing import Queue # q.put()括号里面可以传多种数据类型 #定义队列里面存在数据的个数,先进先出原则 # 1.block、time是搭配使用的 # 2.False:一般单独使用,会立即报错(打印提示信息) q=Queue(3) # #存数据 # q.put('first') q.put({'k':'second'}) q.put(['two',]) q.put(['three',]) # q.put(4,block=True,timeout=3) #*****如果不加block=True,timeout=3备注,一直是收取的状态 # #block=True timeout:意思是管道满了无法再往里面放,并且会等待3秒 # 如果还是满的状态,就会报错(如果不加程序是一直加载状态不会报错) print(q.get()) print(q.get()) print(q.get()) # print(q.get(block=True,timeout=2)) #***如果不跟参数,会打印前3个,后卡在那里.. #block=True,timeout=2,加了如果管道里面没有数据,等待2秒后会报错(提示信息) #注意无论是收还是发:当block=False的时候,是会直接报错,(所以False一般不与time搭配使用) # print(q.get(block=False)
知识点四:生产者消费者模型
1.为什么是生产者消费者模型
生产者:比喻的是程序中负责产生数据的任务
消费者:比喻的是程序中负责处理数据的任务
生产者———>共享的介质(队列)<————消费者
2.为何用
实现生产者与消费者的解耦和,生产者可以不停的生产,消费者也可以不停的消费
从而平衡了生产者的生产能力与消费者消费能力,提升了而整体运行的效率
什么时候用:
当我们程序中存在明显的两类任务,一类是负责产生数据,一类是负责处理数据,此时
就应该考虑使用生产者消费者模型来提升程序的效率
第一个初始版本(分析): from multiprocessing import Queue,Process import time import os import random def producer(name,food,q): for i in range(2): res='第%s食物%s'%(i,food) time.sleep(random.randint(1,3)) q.put(res) #往管道传数据 print('