Python并发编程基础 №③ 信号量(Semaphore),事件(Event),生产者消费者模型 队列(Queue, JoinableQueue)
1.信号量(Semaphore)愿意是旗语,控制一个时刻可以多个进程一起访问
被保护的代码(或数据),是锁的升级版本!
以进ktv包房举例:
1 import time, random 2 from multiprocessing import Process, Semaphore 3 4 5 def enter_ktv(i, sp): 6 sp.acquire() 7 print('顾客%s进入了ktv!'%i) 8 time.sleep(random.randint(i, 19)) 9 print('顾客%s走出了ktv!'%i) 10 sp.release() 11 12 13 if __name__ == '__main__': 14 sp = Semaphore(6) 15 for i in range(18): 16 Process(target=enter_ktv, args=(i, sp)).start()
2、事件(Event)
(1)demo
1 import time, random 2 from multiprocessing import Process 3 from multiprocessing import Event 4 5 e = Event() 6 7 print(e.is_set()) # False 为阻塞状态 8 9 # if not e.is_set(): 10 # e.wait() # 是否阻塞,只有当is_set为False时才阻塞 11 12 e.set() # 设置状态为非阻塞 13 e.wait() 14 15 e.clear() # 设置状态为阻塞 16 17 e.wait() 18 print('128888')
(2)模拟红绿灯系统
1 def car_run(e, idx): 2 if not e.is_set(): 3 print('\33[31m car:%s 停在十字路口,等待绿灯放行!\33[0m' % idx) 4 e.wait() # 阻塞 直到得到一个 事件状态变成 True 的信号 5 print('car:%s 通过十字路口!' % idx) 6 7 def traffic_light(e): 8 while 1: 9 if e.is_set(): # 逻辑与车的相反! 10 e.clear() 11 print('\33[31m红灯亮了\33[0m') 12 else: 13 e.set() 14 print('\33[32m绿灯亮了\33[0m') 15 time.sleep(3) 16 17 18 if __name__ == '__main__': 19 e = Event() 20 light = Process(target=traffic_light, args=(e, )) 21 light.start() 22 23 for i in range(20): 24 car = Process(target=car_run, args=(e, i)) 25 car.start() 26 time.sleep(random.random())
总结:
A、设置状态:set() 和 clear()
B、查看状态: is_set()默认创建时为False,即阻塞
C、阻塞行为:wait() 根据is_set()来决定是否阻塞,False时阻塞,否则放行!
3、进程间的数据传递:Queue
进程间的数据传递可以使用队列,不过不是queue,而是multiprocessing模块中的Queue
1 def consume(idx, q): 2 time.sleep(random.randint(1,2)) 3 knife = q.get() 4 print('\033[32m游侠%s,拿到一把:%s\033[0m'%(idx, knife)) 5 6 7 def produce(name, q): 8 for i in range(10): 9 time.sleep(random.random()) 10 knife = '\033[31m%s做出了一件屠龙宝刀,编号:No%d\033[0m'%(name, i) 11 print(knife) 12 q.put(knife) 13 14 15 if __name__ == '__main__': 16 q = Queue() 17 18 Process(target=produce, args=('Tom', q)).start() 19 20 for i in range(10): 21 Process(target=consume, args=(i, q)).start()
4、生产者消费者模型
1 # 生产者和消费者模型 2 import time, random 3 from multiprocessing import Process, Queue 4 5 6 def produce(q, name): 7 """ 8 生产者的生成行为 9 :return: 产品 10 """ 11 for i in range(10): 12 product = '%s生产了产品%d'%(name, i) 13 print(product) 14 q.put(product) 15 time.sleep(random.random()) 16 17 18 def consume(q, name): 19 """ 20 消费者的消费行为 21 :param q: 22 :return: None 23 """ 24 while 1: 25 p = q.get() 26 if p is None: 27 print('%s消费时,发现没有东西了!'%name) 28 break 29 print('%s消费了-----%s'%(name, p)) 30 time.sleep(random.random()) 31 32 33 if __name__ == "__main__": 34 q = Queue() 35 p1 = Process(target=produce, args=(q, 'John')) 36 p1.start() 37 p2 = Process(target=produce, args=(q, 'Tom')) 38 p2.start() 39 c1 = Process(target=consume, args=(q, '童姥')) 40 c1.start() 41 c2 = Process(target=consume, args=(q, '远方')) 42 c2.start() 43 p1.join() 44 p2.join() 45 q.put(None) 46 q.put(None)
5、JoinableQueue完美解决上述问题
1 import time, random 2 from multiprocessing import Process 3 from multiprocessing import JoinableQueue 4 5 6 def produce(jq): 7 for i in range(10): 8 msg = '记者%d,写了一篇关于太空探索的报告'%i 9 print(msg) 10 jq.put(msg) 11 jq.join() # 阻塞 直到一个队列中的所有数据 全部被处理完毕 12 13 14 def consume(jq, i): 15 while 1: 16 msg = jq.get() 17 print('编辑%s审核了报告:%s'%(i,msg)) 18 time.sleep(random.randint(1, 3)) 19 jq.task_done() 20 21 22 if __name__ == '__main__': 23 jq = JoinableQueue() 24 25 p = Process(target=produce, args=(jq, )) 26 p.start() 27 28 c1 = Process(target=consume, args=(jq, 'c1')) 29 c2 = Process(target=consume, args=(jq, 'c2')) 30 c1.daemon = True 31 c2.daemon = True 32 c1.start() 33 c2.start() 34 35 p.join()