python学习笔记 day36 事件
1. Event事件 ---标志,可以实现异步阻塞
之前input,recv,accpet sleep等都是同步阻塞(写在哪个进程就会阻塞哪个),然后学了Lock锁 和信号量Semophore 都可以实现异步阻塞,同时阻塞多个进程(比如锁 只是同一时间只允许一个进程执行任务,所以比如开10个进程,就会同时异步阻塞九个)然后Semophore信号量可以允许多把钥匙,同一时间多个进程拿到钥匙执行任务,就会异步阻塞其他的进程(只能等着)
现在Event 事件可以完成同时阻塞所有进程(相当于是一个标志,可以理解为交通信号灯,然后开的进程理解为车。交通信号灯,event为红(阻塞)进程,车就不能通过表现为阻塞,event 或交通灯为绿,车进程就可以通过,表现为非阻塞)
from multiprocessing import Event e=Event() # 实例化一个事件,默认阻塞(可以理解为交通信号灯,一开始红灯) e.set() # 设置为非阻塞(交通灯变绿) e.wait() # 默认为阻塞(红灯),set()之后变为非阻塞,(变绿) e.clear() # 设置为阻塞(红灯),刚才的绿灯现在变为i红灯 # e.wait() # clear之后现在wait()就会一直阻塞
运行结果:
2. 使用事件模拟交通路口车辆通过:
思路:
首先实现一个traffic_light()函数,主要是完成交通灯红绿灯转换(三秒轮换),设置事件e的状态 阻塞和非阻塞每三秒转换;
实现car() 完成车辆通过,会用到e的状态,阻塞,非阻塞,非阻塞时wait()直接就不等待,直接执行下面的代码,阻塞时就会一直等待,直到事件e变为非阻塞状态;
在主进程中先开一个子进程,来执行交通灯转换,(由于是死循环,所以需要开一个子进程来完成,否则主进程会一直阻塞,无法执行下面的代码)
然后开100个进程,模拟车,可以利用random模块和time模块设置并发,随机来多少辆车(根据i决定是否来,同时来的车辆i就是并发),然后执行car函数,是否立马通过,取决于e事件的是否阻塞状态,也就是是否为绿灯:
代码实现:
from multiprocessing import Process from multiprocessing import Event import random import time def traffic_light(e): """ 模拟交通灯,实际上是设置事件的阻塞状态,每三秒转换一次,代表红绿灯的转换 :param e: :return: """ while True: # 死循环,红绿灯转换是需要一直工作的,事件e的阻塞状态一直在变(所以该函数需要单独要开一个子进程来实现,否则主进程会一直执行该死循环) if e.is_set(): # 查看事件e的阻塞状态,True代表非阻塞(绿灯) print("绿灯亮") time.sleep(3) # 绿灯亮三秒 e.clear() # 设置为阻塞状态 else: print("红灯亮") time.sleep(3) e.set() # 红灯亮三秒后设置为绿灯(非阻塞) def car(i,e): """ 模拟车辆通过,车辆是否立马通过,取决于红绿灯的状态,也就是进程是否阻塞,取决于事件e的阻塞状态 :param i: :param e: :return: """ e.wait() # 事件e阻塞时,这里会一直等待,直到事件set()也就是设置为非阻塞,才会执行下面的代码,不再等待 print("%s车辆通过"%i) if __name__=="__main__": e=Event() # 实例化一个事件 p=Process(target=traffic_light,args=(e,)) # 单独开一个子进程执行traffic_light()函数,因为该函数是个死循环,绝对不能在主进程中完成的 p.start() for i in range(100): # 创建100个进程(模拟100辆车) if i%random.randint(3,7)==0: # 随机产生并发车辆的数目(有可能同时来3辆,有可能同时来5辆,都不确定) time.sleep(random.randint(1,3)) # 随机睡几秒(比如如果i是5 上面的随机数产生的刚好也是5 那么这个车辆就不会立马来,会先睡几秒,不会是并发的车辆) p=Process(target=car,args=(i,e)) # 并发的车辆(就是没有睡的)开启进程,但是是否立即通过取决于此时事件是否阻塞,如果阻塞就会等三秒,变为非阻塞,并发车辆才会同时通过 p.start()
运行结果:
运行结果也是对的,,直观上好像红灯亮的时候车辆也过,但是(红灯亮的时候是不会立马有车辆通过,会等三秒才会有车辆通过的~)
或者直接把traffic_light()改成:
运行结果:
talk is cheap,show me the code