信号量和事件及队列补充

【一】信号量(了解)

  • 信号量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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值