## 守护进程 ```python def task(name=None,age=None): print("子进程为守护进程") time.sleep(5) print("守护结束",name,age) if __name__=="__main__": print("父进程开始") p=Process(target=task,kwargs={"name":"owen","age":18}) #设置好守护进程,必须在start之前设置 # p.daemon=True p.start() time.sleep(2) print("父进程结束") p.terminate() 'p.terminate()强制结束一个进程,不会清理:p有子进程会变成孤儿进程,如果p有锁,会变成死锁,特别注意!!! #守护进程:子进程守护父进程,父进程结束,子进程没运行完也要结束. ``` ## 并发导致的资源竞争/数据安全问题及互斥锁 ```python 当多个进程同时要操作同一个资源时,将会导致数据错乱的问题 from multiprocessing import Process,Lock import time,random def task(lock): #上锁,本质就是给所有上锁的进程,加个相同协议的标签. lock.acquire() print("hello,i am jerry") time.sleep(random.randint(0,1)) print("age is 18") lock.release() def task2(lock): lock.acquire() print("hello i am owen") time.sleep(random.randint(0,1)) print("age is 19") lock.release() if __name__=="__main__": lock=Lock() p1=Process(target=task,args=(lock,)) p2=Process(target=task2,args=(lock,)) p1.start() p2.start() #不能对同一把锁执行多次acquire,会锁死导致后续加锁程序无法运行 #一次acquire 必须配合一次release! #lock的本质也是将并发强制改成串行执行.同在start方法后面跟join方法一样. """区别在于:1.join是固定了执行顺序,会造成父进程等待子进程 锁依然是公平竞争谁先抢到谁先执行,父进程可以做其他事情 2.最主要的区别:join是把进程的任务全部串行,锁可以锁任意代码 一行也可以 可以自己调整粒度""" 3.互斥锁的粒度:粒度越大意味着锁住的代码越多 效率越低 粒度越小意味着锁住的代码越少 效率越高 ``` ## IPC进程间通讯 ```python from multiprocessing import Process,Manager,Lock import time def task(data,l,i): l.acquire() print(i) name=data["name"] time.sleep(0.1)#延时,这样导致所有进程读到的都是"owen" data["name"]=name+"is" print(i) l.release() if __name__=="__main__": #让Manager开启一个共享的字典 m=Manager() data=m.dict({"name":"owen"}) l=Lock()#锁对象. for i in range(9): p=Process(target=task,args=(data,l,i)) p.start() time.sleep(2) print(data) #Manager没有封装lock方法,需要自己加.Manager开启的共享空间,是在父进程的 #内存中的.父进程结束,子进程没有结束,报错:管道被关闭. #Manager对象下面有三种数据类型容器dict,list,Queue. ``` ## Queue队列 ```python from multiprocessing import Queue q=Queue(3)#创建队列,不指定maxsize,则没有数量限制 #存储元素 q.put("a") q.put("b") q.put("c") # @1:print("执行这一步") print(q.get())#当把这一步注销的时候:@!、@2 q.put("d")#如果容量满了,在调用put时将进入阻塞状态, # 直到有人从队列中拿走数据才会继续执行 # @2:print("这一步不会执行") print(q.get()) print(q.get()) print(q.get()) print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态 #直到有人从存储了新的数据到队列中 才会继续 print("不会往下执行```") q.put("e") #block 表示是否阻塞 默认是阻塞的 #当设置为False 并且队列为空时 抛出异常 q.get(block=True,timeout=2) # block 表示是否阻塞 默认是阻塞的 #当设置为False 并且队列满了时 抛出异常 # q.put("123",block=False,) # timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常 仅在block为True有效 ``` ## 生产者、消费者模型 ```python import time,random from multiprocessing import Process,Queue def consume(q):#消费者 for i in range(10): data=q.get() # time.sleep(random.randint(0,1)) print(data,"消费完第%s个数据"%i) def producer(q):#生产者 for i in range(10): time.sleep(1) data="生产第%s个数据"%i q.put(data) if __name__=="__main__": q=Queue() consu=Process(target=consume,args=(q,)) prod=Process(target=producer,args=(q,)) consu.start() prod.start() #在父进程开了一个Queue队列容器,子进程都可以通过get/put方法访问容器,并且不互斥. # 队列存储/访问顺序是先进先出,后进后出 #生产/消费模型本质就是,开辟一个内存间共享内存空间,有往里写内容,有往外取内容. ```