【一】信号量(了解)
-
信号量Semahpore(同线程一样)
【1】引入
-
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据
【2】例子
-
比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去
-
Lock 锁住一个马桶,同时只能有一个人
-
Semaphore 锁住的是公共厕所,同时可以来一堆人
【3】示例
-
如果指定信号量为3,那么来一个人获得一把锁,计数加1,当计数等于3时,后面的人均需要等待。
-
一旦释放,就有人可以获得一把锁
信号量与进程池的概念很像,但是要区分开,信号量涉及到加锁的概念
from multiprocessing import Process, Semaphore import time import random def go_wc(sem, user): # 【1】对信号量加锁,一个进程占用则锁池 -1 sem.acquire() print(f'{user} 占到一个坑\n') # 模拟每一个人如厕的速度不一样,0代表没拉出来,直接出来了 time.sleep(random.randint(0, 3)) # 【2】释放信号量锁 sem.release() print(f'{user} 站起来了\n') if __name__ == '__main__': # 【一】创建一个信号量的池子 sem = Semaphore(5) p_1 = [] # 【二】十三个子进程 for i in range(13): # 【三】创建子进程 p = Process(target=go_wc, args=(sem, f"user {i}:",)) # 【四】启动子进程 p.start() # 【五】添加到进程列表 p_1.append(p) # 等待所有子进程执行完毕 for i in p_1: i.join() print('=======') user 0: 占到一个坑 user 2: 占到一个坑 user 1: 占到一个坑 user 1: 站起来了 user 4: 占到一个坑 user 3: 占到一个坑 user 6: 占到一个坑 user 2: 站起来了 user 5: 占到一个坑 user 0: 站起来了 user 8: 占到一个坑 user 4: 站起来了 user 7: 占到一个坑 user 6: 站起来了 user 10: 占到一个坑 user 9: 占到一个坑 user 3: 站起来了 user 10: 站起来了 user 11: 占到一个坑 user 8: 站起来了 user 12: 占到一个坑 user 12: 站起来了 user 5: 站起来了 user 7: 站起来了 user 11: 站起来了 user 9: 站起来了 =======
【二】事件
【1】什么是事件
-
Event(同线程一样)
【2】事件处理方法
-
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
-
事件处理的机制:
-
-
全局定义了一个“Flag”
-
如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞
-
如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
-
clear:
-
-
-
-
将“Flag”设置为False
-
-
-
-
set:
-
-
-
-
将“Flag”设置为True
-
-
from multiprocessing import Process, Event, Manager import time import random # 能给你的python解释器终端显示的内容上色 color_red = '\033[31m' color_reset = '\033[0m' color_green = '\033[32m' # 定义车辆行为函数,它会根据事件对象(event)的状态来决定是否等待或通过路口 def car(event, n): ''' 模拟汽车行为 :param event: 事件对象,用于同步操作,红绿灯状态的标识 :param n: 第几辆车的标识 :return: 无返回值 ''' # 创建一个无限循环直到车辆离开 while True: # 如果事件未设置,表示红灯 False if not event.is_set(): # 红灯亮时,车辆等待,并输出提示信息 print(f'{color_red}红灯亮{color_reset},car{n} :>>> 正在等待 ... ') # 阻塞当前进程,等待event被设置(绿灯) event.wait() # 当event被设置后,打印绿灯信息 print(f'{color_green}车 {n} :>>>> 看见绿灯亮了{color_reset}') # 模拟通过路口需要的时间 time.sleep(random.randint(3, 6)) # 防止在sleep期间event状态改变,再次检查状态 if not event.is_set(): continue # 通过路口 print(f'car {n} :>>>> 安全通行') # 退出循环 break # 定义 警车 行为函数, 警车 在红灯时等待一秒后直接通过 def police_car(event, n): ''' 模拟 警车 行为 :param event: 事件对象,用于同步操作,红绿灯状态的标识 :param n: 第几辆车的标识 :return: 无返回值 ''' while True: # 判断是否为红灯 if not event.is_set(): print(f'{color_red}红灯亮{color_reset},car{n} :>>> 正在等待 ... ') # 等待1秒,不完全遵守交通规则 event.wait(1) print(f'灯的是{event.is_set()},警车走了,car{n}') # 通过后立即结束循环 break # 定义交通灯控制函数,周期性切换红绿灯状态 def traffic_lights(event, interval): ''' 模拟 交通灯 行为 :param event: 事件对象,用于同步操作,红绿灯状态的标识 :param interval: 间隔(比如10秒)改变信号灯 :return: 无返回值 ''' # 无限循环,持续控制交通灯状态 while True: # 按照给定间隔(比如10秒)改变信号灯 time.sleep(interval) # 如果当前是绿灯 if event.is_set(): # 切换到红灯状态 # event.is_set() ---->False event.clear() else: # 如果当前是红灯,则切换到绿灯状态 # event.is_set() ----> True event.set() def main(): # 初始化事件对象,初始状态为清除(即红灯) event = Event() # 使用Manager创建一个可跨进程共享的Event对象 # manager = Manager() # event = manager.Event() # 创建并启动多个 警车 进程 # for i in range(5): # police_car_process = Process(target=police_car, args=(event, i)) # police_car_process.start() for i in range(5): police_car_process = Process(target=car, args=(event, i)) police_car_process.start() # 启动交通灯控制进程 # 交通灯变化周期为10秒 traffic_lights_process = Process(target=traffic_lights, args=(event, 10)) traffic_lights_process.start() # 打印分割线,表明程序运行开始 print(' ------------交通开始------------- ') if __name__ == '__main__': main() # ------------交通开始------------- # 红灯亮,car2 :>>> 正在等待 ... # 红灯亮,car0 :>>> 正在等待 ... # 红灯亮,car3 :>>> 正在等待 ... # 红灯亮,car1 :>>> 正在等待 ... # 红灯亮,car4 :>>> 正在等待 ... # 灯的是False,警车走了,car2 # 灯的是False,警车走了,car0 # 灯的是False,警车走了,car3 # 灯的是False,警车走了,car1 # 灯的是False,警车走了,car4 # print("\033[31m这是红色文本\033[0m") # 红色前景色 # print("\033[32m这是绿色文本\033[0m") # 绿色前景色 # print("\033[1;33m这是加粗的黄色文本\033[0m") # 加粗并设置黄色前景色 # print("\033[44m这是蓝色背景文本\033[0m") # 蓝色背景色 # print("\033[34;47m这是蓝色前景色和白色背景色的文本\033[0m") # 蓝色前景和白色背景
【三】队列补充
from queue import Queue, LifoQueue, PriorityQueue # 【一】正常队列 # maxsize 过不给默认值,这个队列的容量就是无限大 # queue = Queue(5) # 放 # queue.put(timeout=1) # queue.put_nowait() # 取 # queue.get(timeout=1) # queue.get_nowait() # 判断队列是否为空 # print(queue.empty()) # 判断是满的 # print(queue.full()) # 获取当前队列中的个数 # print(queue.qsize()) # 【一】Queue 先进先出 print(f'----------Queue-------------') queue_normal = Queue(3) queue_normal.put(1) queue_normal.put(2) queue_normal.put(3) print(queue_normal.get()) print(queue_normal.get()) print(queue_normal.get()) # 【二】LifoQueue 后进先出 print(f'----------LifoQueue-------------') queue_lifo = LifoQueue(3) queue_lifo.put(1) queue_lifo.put(2) queue_lifo.put(3) print(queue_lifo.get()) print(queue_lifo.get()) print(queue_lifo.get()) # 【三】PriorityQueue : 根据优先级数字越小的先出 print(f'----------PriorityQueue-------------') queue_priority = PriorityQueue(3) # 可以给放进队列的元素设置优先级:数字越小优先级越高! queue_priority.put((50, 111)) queue_priority.put((0, 222)) queue_priority.put((100, 333)) print(queue_priority.get()) print(queue_priority.get()) print(queue_priority.get()) # (0, 222) # (50, 111) # (100, 333)