确认多个子进程执行完毕
import demo
from multiprocessing import Process
def target(i):
print(i)
if __name__ == '__main__':
p_l = []
for i in range(5):
p = Process(target=target,args=(i,))
p.start()
p_l.append(p)
# p.join() # 阻塞 主进程 直到子进程执行完毕
for p in p_l:p.join()
print('子进程已经都执行完毕了')
守护进程
有一个参数可以把一个子进程设置为一个守护进程
守护进程是随着主进程的代码结束而结束的,注意只是代码跑完,守护进程就结束,例如如上主进程sleep两秒,子进程每次sleep半秒,那么子进程运行四次后停止。
生产者消费者模型的时候
和守护线程做对比的时候
所有的子进程都必须在主进程结束之前结束,由主进程来负责回收资源
import time
from multiprocessing import Process
def son1(a,b):
while True:
print('is alive')
time.sleep(0.5)
def son2():
for i in range(5):
print('in son2')
time.sleep(1)
if __name__ == '__main__':
p = Process(target=son1,args=(1,2))
p.daemon = True
p.start() # 把p子进程设置成了一个守护进程
p2 = Process(target=son2)
p2.start()
time.sleep(2)
Process对象的其他方法
import time
from multiprocessing import Process
def son1():
while True:
print('is alive')
time.sleep(0.5)
if __name__ == '__main__':
p = Process(target=son1)
p.start() # 异步 非阻塞
print(p.is_alive()) # True False
time.sleep(1)
p.terminate() # 异步的 非阻塞 # 手动退出 和 start对应
print(p.is_alive()) # 进程还活着 因为操作系统还没来得及关闭进程
time.sleep(0.01)
print(p.is_alive()) # 操作系统已经响应了我们要关闭进程的需求,再去检测的时候,得到的结果是进程已经结束了
# 什么是异步非阻塞?
# terminate
面向对象的方式开启进程及总结
import os
import time
from multiprocessing import Process
class MyProcecss2(Process):
def run(self):
while True:
print('is alive')
time.sleep(0.5)
class MyProcecss1(Process):
def __init__(self,x,y):
self.x = x
self.y = y
super().__init__()
def run(self):
print(self.x,self.y,os.getpid())
for i in range(5):
print('in son2')
time.sleep(1)
if __name__ == '__main__':
mp = MyProcecss1(1,2)
mp.daemon = True
mp.start()
print(mp.is_alive())
mp.terminate()
# mp2 = MyProcecss2()
# mp2.start()
# print('main :',os.getpid())
# time.sleep(1)
Process类 开启进程的方式
面向函数
def 函数名:要在子进程中执行的代码
if __name__ == '__main__':
p = Process(target= 函数名,args=(参数1,))
面向对象
class 类名(Process):
def __init__(self,参数1,参数2): # 如果子进程不需要参数可以不写
self.a = 参数1
self.b = 参数2
super().__init__()
def run(self):
#要在子进程中执行的代码
#实例化对象p
p = 类名(参数1,参数2)
#Process提供的操作进程的方法
p.start() 开启进程 异步非阻塞
p.terminate() 结束进程 异步非阻塞
p.join() 同步阻塞
p.isalive() 获取当前进程的状态
daemon = True 设置为守护进程,守护进程永远在主进程的代码结束之后自动结束
锁
并发 能够做的事儿
1.实现能够响应多个client端的server
2.抢票系统
import time
import json
from multiprocessing import Process,Lock
#查票需要并发
def search_ticket(user):
with open('ticket_count') as f:
dic = json.load(f)
print('%s查询结果 : %s张余票'%(user,dic['count']))
#购票改变了数据,需要串行,这里要加锁
def buy_ticket(user,lock):
# with lock:
# lock.acquire() # 给这段代码加上一把锁
time.sleep(0.02)
with open('ticket_count') as f:
dic = json.load(f)
if dic['count'] > 0:
print('%s买到票了'%(user))
dic['count'] -= 1
else:
print('%s没买到票' % (user))
time.sleep(0.02)
with open('ticket_count','w') as f:
json.dump(dic,f)
# lock.release() # 给这段代码解锁
def task(user, lock):
search_ticket(user)
with lock:
buy_ticket(user, lock)
if __name__ == '__main__':
lock = Lock()
for i in range(10):
p = Process(target=task,args=('user%s'%i,lock))
p.start()
总结:
1.如果在一个并发的场景下,涉及到某部分内容
# 是需要修改一些所有进程共享数据资源
# 需要加锁来维护数据的安全
2.在数据安全的基础上,才考虑效率问题
3.同步存在的意义
# 数据的安全性
在主进程中实例化 lock = Lock()
把这把锁传递给子进程
在子进程中 对需要加锁的代码 进行 with lock:
# with lock相当于lock.acquire()和lock.release()
在进程中需要加锁的场景
# 共享的数据资源(文件、数据库)
# 对资源进行修改、删除操作
加锁之后能够保证数据的安全性 但是也降低了程序的执行效率
进程之间的通信
进程之间的数据隔离
from multiprocessing import Process
n = 100
def func():
global n
n -= 1
if __name__ == '__main__':
p_l = []
for i in range(10):
p = Process(target=func)
p.start()
p_l.append(p)
for p in p_l:p.join()
print(n)
通信——进程之间的通信——IPC(inter process communication)
速度快
锁问题解决
IPC机制
进程彼此之间互相隔离,要实现进程间通信(IPC),
multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
共享内存空间
队列=管道+锁
from multiprocessing import Queue
# 占用的内存,最好小数据,消息数据,下载地址
# Queue(限制队列里面的个数)
# 先进先出
q = Queue(3)
# 添加
q.put('a')
q.put('b')
q.put({'x':2})
print('-------')
# q.put('篮子满了')
print('==========')
# 队列满了,相当于锁了
# 提取
print(q.get())
print(q.get())
print(q.get())
# # 队列为空,等待加入,也会阻塞,相当于锁了
print('队列为空')
print(q.get())
生产者消费者模型
- 什么是生产者消费者模型
生产者:代指生产数据的任务
消费者:代指处理数据的任务
该模型的工作方式:
生产者生产数据传递消费者处理
实现方式:
生产者---->队列<------消费者
厨师----》外卖小哥和外卖平台<-----消费者
厨师不影响生产效率 不用等厨师炒完这道菜
可以不停的炒菜 就可以点别的菜
炒好的菜可以给
外卖小哥 - 为何要用
当程序中出现明细的两类任务,一类负责生产数据,一类负责处理数据
就可以引入生产者消费者模型来实现生产者与消费者的解耦合,平衡生产能力与消费能力,从提升效率 - 如何用
方法1: Queue
import time,random
from multiprocessing import Process,Queue
def producer(name,food,q):
for i in range(10):
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()
if res is None:
break
# 模拟处理数据的时间
time.sleep(random.randint(1, 3))
print('吃货%s吃了%s'%(name,res))
if __name__ == '__main__':
q= Queue()
# 生产者
p1 = Process(target=producer,args=('大海','包子',q))
p2 = Process(target=producer,args=('中海','辣椒炒肉',q))
p3 = Process(target=producer,args=('小海','土豆丝',q))
# 消费者
c1 = Process(target=consumer, args=('夏洛', q))
c2 = Process(target=consumer, args=('西施', q))
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
# 等待生产者生成完成
p1.join()
p2.join()
p3.join()
# 生产者生成完成
# 还生成一个多余None给消费者
q.put(None)
q.put(None)
print('主')
方法2: JoinableQueue
import time,random
from multiprocessing import Process,JoinableQueue
def producer(name,food,q):
for i in range(10):
res = '%s%s'%(food,i)
# 模拟生产数据的时间
time.sleep(3)
q.put(res)
print('厨师%s生成了%s'%(name,res))
def consumer(name,q):
while True:
# 订单都没了还在等,队列里面空了
res = q.get()
# 模拟处理数据的时间
time.sleep(3)
print('吃货%s吃了%s'%(name,res))
# 每次完成队列取一次,往q.join() ,取干净了q.join()运行完
q.task_done()
if __name__ == '__main__':
start = time.time()
q= JoinableQueue()
# 生产者
p1 = Process(target=producer,args=('大海','包子',q))
p2 = Process(target=producer,args=('中海','辣椒炒肉',q))
p3 = Process(target=producer,args=('小海','土豆丝',q))
# 消费者
c1 = Process(target=consumer, args=('夏洛', q))
c2 = Process(target=consumer, args=('西施', q))
# #3.守护进程的作用: 主进程死了,消费者子进程也跟着死
# #把消费者变成守护进程
c1.daemon = True
c2.daemon = True
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
# 等待生产者生成完成
p1.join()
p2.join()
p3.join()
# 生产者生成完成
# 菜全部上座了
# 消费者task_done给q.join()发信号
# 生产者运行完?1,2
q.join()
# 消费者吃完?1,2 但是while卡住了
# 意味着print('主')执行主进程运行完了,生产者运行完了
# 消费者也吃完了
# 盘子都空了
# 但是消费者还是阻塞,可以用守护进程结束掉子进程
print('主',time.time()-start)