• 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('33[31m剩余票数%s33[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('33[31m用户%s购票成功33[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('33[31m红灯亮33[0m,car%s等着' % n)
     9             e.wait()    # 阻塞,等待is_set()的值变成True,模拟信号灯为绿色
    10             print('33[32m车%s 看见绿灯亮了33[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('##########')
    
    
    
  • 相关阅读:
    MongoDB面试题
    spider 爬虫文件基本参数(3)
    命令行工具(2)
    初始scrapy,简单项目创建和CSS选择器,xpath选择器(1)
    数据分析实例(离海洋距离与最高温度之间的关系分析)
    路飞业务分析
    MYSQL 主从复制,读写分离(8)
    pyquery 学习
    selenium case报错重新执行
    python小技巧
  • 原文地址:https://www.cnblogs.com/huningfei/p/9188434.html
Copyright © 2020-2023  润新知