9-2 事件,信号量,队列,锁
一 锁(Lock)
当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。就会用到锁
例如:买火车票,我现在只有一张票,10个人来买,如果不加锁,就会显示10个人都买到
1 from multiprocessing import Process,Lock 2 import time,json,random 3 def search():#查票 4 dic=json.load(open('db')) 5 print('\033[31m剩余票数%s\033[0m' %dic['count']) 6 7 def get(num):#买票 8 dic=json.load(open('db')) 9 time.sleep(random.random()) #模拟读数据的网络延迟 10 if dic['count'] >0: 11 dic['count']-=1 12 time.sleep(random.random()) #模拟写数据的网络延迟 13 json.dump(dic,open('db','w')) 14 print('\033[31m用户%s购票成功\033[0m'%num) 15 16 def task(num,lock): 17 search() 18 lock.acquire() 19 get(num) 20 lock.release() 21 22 if __name__ == '__main__': 23 lock = Lock() 24 for i in range(10): #模拟并发10个客户端抢票 25 p=Process(target=task,args = (i,lock)) 26 p.start()
还有我开启三个进程让一一对应启动和结束同样也用到了锁
1 import os 2 import time 3 import random 4 from multiprocessing import Process,Lock 5 6 def work(n,lock): 7 lock.acquire()#取的钥匙 8 print('%s:%s is running'%(n,os.getpid())) 9 time.sleep(random.random()) 10 print('%s:%s is done' %(n,os.getpid())) 11 lock.release()#释放 12 if __name__ == '__main__': 13 lock=Lock() 14 for i in range(3): 15 p=Process(target=work,args=(i,lock)) 16 p.start() 17 18 结果: 19 0:25068 is running 20 0:25068 is done 21 1:24296 is running 22 1:24296 is done 23 2:24092 is running 24 2:24092 is done
二 事件(Event)(用的很少)
# 事件内部内置了一个标志
# wait 方法 如果这个标志是True,那么wait == pass
# wait 方法 如果这个标志是False,那么wait就会陷入阻塞,一直阻塞到标志从False变成True
# 一个事件在创建之初 内部的标志默认是False
# Flase -> True set()
# True -> False clear()
例子:红路灯模型
说明:
# 10个进程 模拟车 :车的行走要依靠当时的交通灯
# 交通灯是绿灯 车就走
# 交通灯是红灯 车就停 停到灯变绿
# wait 来等灯
# set clear 来控制灯
1 from multiprocessing import Process, Event 2 import time, random 3 4 def car(e, n): 5 while True: 6 if not e.is_set(): 7 # 进程刚开启,is_set()的值是Flase,模拟信号灯为红色 8 print('\033[31m红灯亮\033[0m,car%s等着' % n) 9 e.wait() # 阻塞,等待is_set()的值变成True,模拟信号灯为绿色 10 print('\033[32m车%s 看见绿灯亮了\033[0m' % n) 11 time.sleep(random.randint(3, 6)) 12 if not e.is_set(): #如果is_set()的值是Flase,也就是红灯,仍然回到while语句开始 13 continue 14 print('车开远了,car', n) 15 break 16 17 def traffic_lights(e, inverval): 18 while True: 19 time.sleep(inverval) # 先睡3秒 20 if e.is_set(): # 标志是True 21 print('######', e.is_set()) 22 e.clear() # ---->将is_set()的值设置为False 23 else: # 标志是False 24 e.set() # ---->将is_set()的值设置为True 25 print('***********',e.is_set()) 26 27 28 if __name__ == '__main__': 29 e = Event() #e就是事件 30 t = Process(target=traffic_lights, args=(e, 3)) # 创建一个进程控制红绿灯 31 for i in range(10): 32 p=Process(target=car,args=(e,i,)) # 创建10个进程控制10辆车 33 p.start() 34 t.start() 35 36 print('============》')
三 队列 (Queue)
q.get( [ block [ ,timeout ] ] )
返回q中的一个项目。如果q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控制阻塞行为,默认为True. 如果设置为False,将引发Queue.Empty异常(定义在Queue模块中)。timeout是可选超时时间,用在阻塞模式中。如果在制定的时间间隔内没有项目变为可用,将引发Queue.Empty异常。
q.get_nowait( )
同q.get(False)方法。
q.put(item [, block [,timeout ] ] )
将item放入队列。如果队列已满,此方法将阻塞至有空间可用为止。block控制阻塞行为,默认为True。如果设置为False,将引发Queue.Empty异常(定义在Queue库模块中)。timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引发Queue.Full异常。
创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。
例子:
1 from multiprocessing import Queue,Process 2 3 def func(q,num): 4 try: 5 t = q.get_nowait() #拿一张票 不阻塞直接报错同q.get(False)
6 print("%s抢到票了"%num) 7 except:pass 8 9 if __name__ == '__main__': 10 q = Queue() 11 q.put(1) #往里面放一张票 12 for i in range(10):#创建了10个人去抢一张票 13 Process(target=func,args=(q,i)).start() 14 15 16 #结果是只有一个人买到了票
四信号量 (Semaphore)了解即可,很少用
如:
互斥锁同时只允许一个线程更改数据,而信号量Semaphore是同时允许一定数量的线程更改数据 。
假设商场里有4个迷你唱吧,所以同时可以进去4个人,如果来了第五个人就要在外面等待,等到有人出来才能再进去玩
1 from multiprocessing import Process,Semaphore 2 import time,random 3 def go_ktv(sem,user): 4 sem.acquire() 5 print('%s占到一件ktv小屋' %user) 6 time.sleep(random.randint(3,5)) 7 sem.release() 8 print('%s走出小屋'%user) 9 if __name__ == '__main__': 10 sem=Semaphore(4) 11 p_l=[] 12 for i in range(13): 13 p=Process(target=go_ktv,args=(sem,'user%s' %i,)) 14 p.start() 15 p_l.append(p) 16 for i in p_l: 17 i.join() 18 print('##########')