【一】信号量(了解)
-
信号量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】对信号量加锁,一个进程占用则锁池 -1sem.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:# 如果事件未设置,表示红灯 Falseif 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() ---->Falseevent.clear()else:# 如果当前是红灯,则切换到绿灯状态# event.is_set() ----> Trueevent.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)