目录
一、信号量 multiprocess.Semaphore
意义:一套资源、代码同一时间只能被n个人访问、n个进程执行
格式:
from multiprocessing import Process
from multiprocessing import Semaphore
def ktv(i,sem):
sem.acquire() 获取钥匙
print('%s走进ktv'%i)
print('%s走出ktv'%i)
sem.release() 还钥匙
if __name__ == '__main__' :
sem = Semaphore(4) 一共有几把钥匙
for i in range(20):
p = Process(target=ktv,args=(i,sem))
p.start()
二、事件 —— multiprocess.Event
事件:通过一个信号来控制多个进程同时执行或者阻塞,一个事件被创建之后,默认是阻塞状态,一个事件被创建之后,默认是阻塞状态
格式:
from multiprocessing import Event
e = Event() 创建了一个事件
print(e.is_set()) False 查看一个事件的状态,默认被设置成阻塞
e.set() 将这个事件的状态改为True
print(e.is_set()) True
e.wait() 是依据e.is_set()的值来决定是否阻塞的
print(123456)
e.clear() 将这个事件的状态改为False
print(e.is_set()) False
e.wait() 等待(等待时为阻塞)事件的信号被变成True
print('*'*10)
红绿灯作业:
import time
import random
from multiprocessing import Event,Process
def cars(e,i):
if not e.is_set():
print('car%i在等待'%i)
e.wait() # 阻塞 直到得到一个 事件状态变成 True 的信号
print('\033[0;32;40mcar%i通过\033[0m' % i)
def light(e):
while True:
if e.is_set():
e.clear()
print('\033[31m红灯亮了\033[0m')
else:
e.set()
print('\033[32m绿灯亮了\033[0m')
time.sleep(2)
if __name__ == '__main__':
e = Event()
traffic = Process(target=light,args=(e,))
traffic.start()
for i in range(20):
car = Process(target=cars, args=(e,i))
car.start()
time.sleep(random.random())
三、进程间通信——队列
队列 先进先出,队列空了继续取q.get()数据会阻塞,队列满了继续存q.put()数据会阻塞
q.full() # 队列是否满了返回True or False 不准确
from multiprocessing import Queue,Process
def produce(q):
q.put('hello')
def consume(q):
print(q.get())
if __name__ == '__main__':
q = Queue()
p = Process(target=produce,args=(q,))
p.start()
c = Process(target=consume, args=(q,))
c.start()
四、生产者消费者模型JoinableQueue
get 、 task_done 连用。put 、join 连用
q.task_done()
使用者使用此方法发出信号,表示q.get()返回的项目已经被处理。如果调用此方法的次数大于从队列中删除的项目数量,将引发ValueError异常。
q.join()
生产者将使用此方法进行阻塞,直到队列中所有项目均被处理。阻塞将持续到为队列中的每个项目均调用q.task_done()方法为止。
import time
import random
from multiprocessing import Process,JoinableQueue
def consumer(q,name):
while True:
food = q.get()
print('\033[31m%s消费了%s\033[0m' % (name,food))
time.sleep(random.randint(1,3))
q.task_done() # count - 1
def producer(name,food,q):
for i in range(4):
time.sleep(random.randint(1,3))
f = '%s生产了%s%s'%(name,food,i)
print(f)
q.put(f)
q.join() # 阻塞 直到一个队列中的所有数据 全部被处理完毕
if __name__ == '__main__':
q = JoinableQueue(20)
p1 = Process(target=producer,args=('Egon','包子',q))
p2 = Process(target=producer, args=('wusir','泔水', q))
c1 = Process(target=consumer, args=(q,'alex'))
c2 = Process(target=consumer, args=(q,'jinboss'))
p1.start()
p2.start()
c1.daemon = True # 设置为守护进程 主进程中的代码执行完毕之后,子进程自动结束
c2.daemon = True
c1.start()
c2.start()
p1.join()
p2.join() # 感知一个进程的结束
代码解释:
# 在消费者这一端:
# 每次获取一个数据
# 处理一个数据
# 发送一个记号 : 标志一个数据被处理成功
# 在生产者这一端:
# 每一次生产一个数据,
# 且每一次生产的数据都放在队列中
# 在队列中刻上一个记号
# 当生产者全部生产完毕之后,
# join信号 : 已经停止生产数据了
# 且要等待之前被刻上的记号都被消费完
# 当数据都被处理完时,join阻塞结束
代码过程:
consumer 中把所有的任务消耗完
producer 端 的 join感知到,停止阻塞
所有的producer进程结束
主进程中的p.join结束
主进程中代码结束
守护进程(消费者的进程)结束