python进程-守护进程原理-,互斥锁与join区别-队列-生产者消费者模式
1.守护进程
守护进程其实就是一个‘子进程’
守护=》伴随
1.守护进程会伴随主进程的代码运行完毕后而死掉
2.守护进程内无法再开启子进程,否则抛出异常
2.为何用守护进程:
关键字就两个:
进程:
当父进程需要将一个任务并发出去执行,需要将该任务放在一个子进程里
守护:
当该子进程内的代码在父进程代码运行完毕后就没存在的意义了。
就应该将该子进程设置为守护进程,会在父进程代码结束后死掉
# from multiprocessing import Process
# import time,os
#
# def task(name):
# print('%s is running' %name)
# time.sleep(3)
#
# if __name__ == '__main__':
# p1=Process(target=task,args=('守护进程',))
# p2=Process(target=task,args=('正常的子进程',))
#
# p1.daemon = True # 一定要放到p.start()之前
# p1.start()
# p2.start()
#
# print('主') #主进程代码运行完毕,守护进程就会结束
# 一定要放到p.start()之前
# p1.start()
# p2.start()
#
# print('主') #主进程代码运行完毕,守护进程就会结束
互斥锁:可以将要执行任务的部分代码(只涉及到修改共享数据的代码)变成串行进程操作
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,但牺牲了速度却保证了数据安全。
join:是要执行任务的所有代码整体串行
#模拟买票场景-多进程并发-互斥锁
from multiprocessing import Process,Lock
import json
import os
import time
import 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() # 互斥锁不能连续的acquire,必须是release以后才能重新acquire
get()
mutex.release()
# with mutex: 互斥锁 简单写法
# get()
if __name__ == '__main__':
mutex=Lock()
for i in range(10):
p=Process(target=task,args=(mutex,))
p.start()
# p.join()
from multiprocessing import Process,Lock
import json
import os
import time
import 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() # 互斥锁不能连续的acquire,必须是release以后才能重新acquire
get()
mutex.release()
# with mutex: 互斥锁 简单写法
# get()
if __name__ == '__main__':
mutex=Lock()
for i in range(10):
p=Process(target=task,args=(mutex,))
p.start()
# p.join()
IPC(队列):进程间的通信,要实现进程间通信(IPC),有两种实现方式
multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
1.PIPE 管道
2.queue:PIPE+锁
注意:1.队列占用的是内存空间,
2.不应该往队列中放大数据,应该值存放数量较小的消息
from multiprocessing import Queue
#掌握
# q=Queue(3) #可以指定队列大小
# q.put('xxx')
# q.put({'s':'sencond'})
# q.put(['faga'])
# q.put(4) #设置最大3个,锁机制,到第四个时候阻塞主,直到取走一个后才能再放进一个
#
#
#
# print(q.get())
# print(q.get())
# print(q.get())
# # print(q.get()) #超过取值,会阻塞
#了解知识
# q = Queue(3) # 超时时间只有block=True才有意义 block=False不会阻塞,直接报错
# q.put('ffa', block=True, timeout=3) # 队列满了后 阻塞主,再来一个,等待三秒没人来取就会报错
# q.put({'k': 'sencond'}, block=True, timeout=3)
# q.put(['third', ], block=True, timeout=3)
# print('===>')
# q.put(4,block=True,timeout=3)
# print(q.get(block=True,timeout=3))
# print(q.get(block=True,timeout=3))
# print(q.get(block=True,timeout=3))
# print(q.get(block=True,timeout=3))
#block=False简写版:
q=Queue(3) #先进先出
q.put_nowait('first') #q.put('first',block=False,)
q.put_nowait(2)
q.put_nowait(3)
# q.put_nowait(4)
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())
#掌握
# q=Queue(3) #可以指定队列大小
# q.put('xxx')
# q.put({'s':'sencond'})
# q.put(['faga'])
# q.put(4) #设置最大3个,锁机制,到第四个时候阻塞主,直到取走一个后才能再放进一个
#
#
#
# print(q.get())
# print(q.get())
# print(q.get())
# # print(q.get()) #超过取值,会阻塞
#了解知识
# q = Queue(3) # 超时时间只有block=True才有意义 block=False不会阻塞,直接报错
# q.put('ffa', block=True, timeout=3) # 队列满了后 阻塞主,再来一个,等待三秒没人来取就会报错
# q.put({'k': 'sencond'}, block=True, timeout=3)
# q.put(['third', ], block=True, timeout=3)
# print('===>')
# q.put(4,block=True,timeout=3)
# print(q.get(block=True,timeout=3))
# print(q.get(block=True,timeout=3))
# print(q.get(block=True,timeout=3))
# print(q.get(block=True,timeout=3))
#block=False简写版:
q=Queue(3) #先进先出
q.put_nowait('first') #q.put('first',block=False,)
q.put_nowait(2)
q.put_nowait(3)
# q.put_nowait(4)
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())
1.什么是生产者消费者模型
生产者:比喻的是程序中负责产生数据的任务
消费者:比喻的是程序中负责处理数据的任务
生产者=》共享的介质(队列)《=消费者
2.为何用:
实现了生产者与消费者的解耦和,生产者可以不停的生产,消费者也可以不停的消费
从而平衡了生产者的生产能力与消费者消费能力,提升了程序整体运行的效率
(就是在生产和消费同时进行并实现队列通信,两者之间就需要一个机制来协调管理)
3.什么时候用?
当我们的程序中存在明显的两类任务,一类负责产生数据,另外一类负责处理数据
此时就应该考虑使用生产者消费者模型来提升效率的效率
JoinableQueue 方法
模拟生产者和消费者环境
from multiprocessing import JoinableQueue, Process
import time, os, random
def producer(name, food, q):
for i in range(3):
res = '%s%s' % (food, i)
time.sleep(random.randint(1, 3))
q.put(res)
print('\033[42m%s生产了%s\033[0m' % (name, res))
def consumer(name, q):
while True:
res = q.get()
if res is None: break
time.sleep(random.randint(1, 3))
print('\033[44m%s吃了%s\033[0m' % (name, res))
q.task_done() #告诉队列取走数据
if __name__ == '__main__':
q = JoinableQueue() #可以检测到队列里有多少个值,取走一个减一个
#有个join方法,检测队列值的值取完可以结束
# 生产者
p1 = Process(target=producer, args=('egon', '包子', q))
p2 = Process(target=producer, args=('杨军', '泔水', q))
p3 = Process(target=producer, args=('猴老师', '翔', q))
# 消费者
c1 = Process(target=consumer, args=('alex', q))
c2 = Process(target=consumer, args=('wupeiqi', q))
c1.daemon=True #开启守护进程
c2.daemon=True #父进程结束,子进程也结束
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
p1.join()
p2.join()
p3.join()
q.join() #原地等待队列里的值被取干净后,才运行下面代码。
# 消费者进程也就应该要结束,所以需要
print('主')
#总结:
#主进程的代码运行完毕-->(生产者运行完毕)+列队中的数据也被取干净了->消费者最后也存在意思了
#告诉队列取走数据
if __name__ == '__main__':
q = JoinableQueue() #可以检测到队列里有多少个值,取走一个减一个
#有个join方法,检测队列值的值取完可以结束
# 生产者
p1 = Process(target=producer, args=('egon', '包子', q))
p2 = Process(target=producer, args=('杨军', '泔水', q))
p3 = Process(target=producer, args=('猴老师', '翔', q))
# 消费者
c1 = Process(target=consumer, args=('alex', q))
c2 = Process(target=consumer, args=('wupeiqi', q))
c1.daemon=True #开启守护进程
c2.daemon=True #父进程结束,子进程也结束
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
p1.join()
p2.join()
p3.join()
q.join() #原地等待队列里的值被取干净后,才运行下面代码。
# 消费者进程也就应该要结束,所以需要
print('主')
#总结:
#主进程的代码运行完毕-->(生产者运行完毕)+列队中的数据也被取干净了->消费者最后也存在意思了
总结: 守护进程:deamon=True
互斥锁:Lock
队列-PIPE+锁: Queue():q.put() q.get()
JoinableQueue :task_done告诉队列取走数据
join 原地等待队列中的数据取完后再运行下面代码,阻塞