1.守护进程(了解)
主进程创建守护进程
其一:守护进程会在主进程代码执行(读取完毕)结束后就终止
其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
注意:进程之间是互相独立的,主进程代码运行结束(读取完毕),守护进程就会立刻终止
from multiprocessing import Process import time import random class Piao(Process): def __init__(self,name): self.name=name super().__init__() def run(self): print('%s is piaoing' %self.name) time.sleep(random.randrange(1,3)) print('%s is piao end' %self.name) p=Piao('Tom') p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行 p.start() print('主')
#主进程代码运行完毕,守护进程就会结束 from multiprocessing import Process from threading import Thread import time def foo(): print(123) time.sleep(1) print("end123") def bar(): print(456) time.sleep(3) print("end456") p1=Process(target=foo) p2=Process(target=bar) p1.daemon=True p1.start() p2.start() print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止 迷惑人的例子
2.互斥锁
先来想,进程与进程之间内存空间相互独立,如何实现进程与进程之间的数据沟通与交互呢?来看具体实例,有一台打印机,有三个程序需要打印各自的内容,你先来写一下怎么先让代码跑起来,每个程序都能打印到吧
from multiprocessing import Process import time,random def printer1(): print('task1 name>>') time.sleep(random.randint(1,3)) print('task1 age>>:') time.sleep(random.randint(1,3)) print('task1 gender>>:') time.sleep(random.randint(1,3)) def printer2(): print('task2 name>>') time.sleep(random.randint(1, 3)) print('task2 age>>:') time.sleep(random.randint(1, 3)) print('task2 gender>>:') time.sleep(random.randint(1, 3)) def printer3(): print('task3 name>>') time.sleep(random.randint(1, 3)) print('task3 age>>:') time.sleep(random.randint(1, 3)) print('task3 gender>>:') time.sleep(random.randint(1, 3)) if __name__ == '__main__': p1=Process(target=printer1) p2=Process(target=printer2) p3=Process(target=printer3) p1.start() p1.join() p2.start() p2.join() p3.start() p3.join() #这个方法利用join虽然实现了打印出来的结果不乱,但是极其的不公平,人为指定了进程产生的顺序,整体都是串行执行,效率太低!
from multiprocessing import Process,Lock import time,random def printer1(mutex): mutex.acquire()#抢锁执行 print('task1 name>>') time.sleep(random.randint(1,3)) print('task1 age>>:') time.sleep(random.randint(1,3)) print('task1 gender>>:') time.sleep(random.randint(1,3)) mutex.release()#释放锁给其他人争抢 def printer2(mutex): mutex.acquire() print('task2 name>>') time.sleep(random.randint(1, 3)) print('task2 age>>:') time.sleep(random.randint(1, 3)) print('task2 gender>>:') time.sleep(random.randint(1, 3)) mutex.release() def printer3(mutex): mutex.acquire() print('task3 name>>') time.sleep(random.randint(1, 3)) print('task3 age>>:') time.sleep(random.randint(1, 3)) print('task3 gender>>:') time.sleep(random.randint(1, 3)) mutex.release() if __name__ == '__main__': mutex=Lock() p1=Process(target=printer1,args=(mutex,)) p2=Process(target=printer2,args=(mutex,)) p3=Process(target=printer3,args=(mutex,)) p1.start() p2.start() p3.start() #此法使得进程的产生是公平的,进程之间公平的争抢锁,谁先抢到谁就先用,其他的人只能等着抢到锁的人执行完自己的代码,释放锁之后,再去争抢锁执行代码释放锁如此往返~~~
模拟抢票 from multiprocessing import Process,Lock import json,os,time,random def search(): time.sleep(random.randint(1,3)) with open('a.txt','r',encoding='utf-8')as f : ticket=json.load(f) print('%s 查看到票数为:%s'%(os.getpid(),ticket['count'])) def get(): with open('a.txt','r',encoding='utf-8')as f : ticket=json.load(f) time.sleep(random.randint(1,3)) if ticket['count']>0: ticket['count']-=1 time.sleep(random.randint(1,2)) with open('a.txt','w',encoding='utf-8')as f: json.dump(ticket,f) print('%s购票成功'%os.getpid()) else:print('%s 没有票了'%os.getpid()) def task(mutex): search() mutex.acquire() get() mutex.release() if __name__ == '__main__': mutex=Lock() for i in range(20): p = Process(target=task, args=(mutex,)) p.start()
互斥锁:强调——必须是acquire()一次,然后release()释放一次。才能继续acquire(),不能连续的acquire()与join()大前提是一样的,都是将并发变成串行,从而保证有序区别在于:join()是人为指定了执行顺序(启动顺序)互斥锁则是所有程序平等竞争(都先启动),谁先抢到谁先执行,将进程中的某一部分由并发变成串行串行在某些场景下虽然降低了效率,但是却提高了安全性,比如打印机打印阶段,抢票购票阶段
3.IPC通信(基于信息的通信)
先来想上面的互斥锁的例子是通过硬盘里的文件(硬件都是共享的嘛~)来实现不同进程之间的交互,但是这样效率实在太低,反复的读写文件将产生的大量的I/O操作~所以我们需要找到一块地盘能够是进程共享的资源,并且读取速度快,还能帮我们考虑锁的问题保证信息的安全准确——IPC:进程共享,并且是内存空间,能自动帮我们处理锁的问题,(由于此法是基于内存空间的共享,所以不能用来传输大数据,只能用来存放进程之间沟通的消息数据)——运用模块Queue队列
IPC通信之队列(Queue) from multiprocessing import Queue q=Queue(3)#规定队列长度 #放数据 队列中存放的数据遵循先进先出原则 q.put('first') q.put({'num':'second'}) q.put('三') #q.put(4) 阻塞 #取数据 队列中的数据取一个就少一个在总数固定的情况下 print(q.get()) #first print(q.get()) #{'num':'second'} print(q.get()) #三 队列:1.共享的内存空间,自动处理锁的问题(占用的是内存资源!!!) 强调:1.队列用来存放进程之间沟通的消息,数据量不应该过大,2.maxsize的值超过内存限制就变得毫无意义了
4.基于队列的生产者消费者模型
模型解析:
1.生产者:制造产生数据
2.消费者:处理生产者制造出来的数据
模型三要素:1.生产者 2.消费者 3.队列(生产者消费者之间的运输运输工具)
from multiprocessing import Process,Queue import time,random def producer(name,food,q): for i in range(1,5): res='%s%s'%(food,i) time.sleep(random.randint(1,3)) q.put(res) #将数据放入队列中 print('%s生产了%s'%(name,res)) def consumer(name,q): while True: res=q.get()#从队列中拿取数据 time.sleep(random.randint(1,3)) print('%s消费了%s'%(name,res)) if __name__ == '__main__': q=Queue() #实例化出队列 p1=Process(target=producer,args=('Tom','包子',q)) p2=Process(target=producer, args=('jerry', '馒头', q)) p3=Process(target=producer, args=('word', '面条', q)) c1=Process(target=consumer,args=('jack',q)) c2=Process(target=consumer,args=('alex',q)) p1.start() p2.start() p3.start() c1.start() c2.start()
优点:实现了进程与进程之间的解耦和,不需要等生产者也不需要等消费者消费,各自处理各自的,由队列来与双方打交道即可,平衡了生产力与消费水平~