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('##########')

 


 

posted @ 2018-06-15 17:48  huningfei  阅读(164)  评论(0编辑  收藏  举报
levels of contents