python信号量、条件变量、事件

一.信号量

信号量和锁相似,锁同一时间只允许一个对象(进程)通过,信号量同一时间允许多个对象(进程)通过。

1.semaphore信号量原理

多线程同时运行,能提高程序的运行效率,但是并非线程越多越好,而semaphore信号量可以通过内置计数器来控制同时运行线程的数量,启动线程(消耗信号量)内置计数器会自动减一,线程结束(释放信号量)内置计数器会自动加一;内置计数器为零,启动线程会阻塞,直到有本线程结束或者其他线程结束为止;

2.semaphore信号量相关函数介绍

acquire() — 消耗信号量,内置计数器减一;

release() — 释放信号量,内置计数器加一;

在semaphore信号量有一个内置计数器,控制线程的数量,acquire()会消耗信号量,计数器会自动减一;release()会释放信号量,计数器会自动加一;当计数器为零时,acquire()调用被阻塞,直到release()释放信号量为止。
例子:

import threading
import time


def run(n,x):
    semaphore.acquire()
    print(n)
    time.sleep(x)
    semaphore.release()
if __name__ == '__main__':
    semaphore = threading.Semaphore()
    for i in range(50):
        t=threading.Thread(target=run, args=(i,))
        t.start()

二.条件变量

Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将自己生成一个RLock实例。

Condition()包括以下几点:

1.acquire(): 线程锁
2.release(): 释放锁
3.wait(timeout): 线程挂起,直到收到一个notify通知或者超时才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。
4.notify(n=1): 通知其他线程,那些挂起的线程接到这个通知之后会开始运行,默认是通知一个正等待该condition的线程,最多则唤醒n个等待的线程。notify()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。notify()不会主动释放Lock。
notifyAll(): 如果wait状态线程比较多,notifyAll的作用就是通知所有线程

例如:

import threading
import time


def run(x):
    #lock.acquire()
    con.acquire()
    print(f'线程{x}')
    con.notify()
    print(f'线程{x}挂起')
    con.wait()
    time.sleep(1)
    print(f'线程{x}再次启动')
    con.notify()
    con.release()
    #lock.release()
def run2(x):
    #lock.acquire()
    con.acquire()
    print(f'线程{x}')
    con.notify()
    print(f'线程{x}挂起')
    con.wait()
    time.sleep(1)
    print(f'线程{x}再次启动')
    con.notify()
    con.release()
    #lock.release()
if __name__ == '__main__':
    con = threading.Condition()
    #for i in range(50):
        #lock=threading.Lock()

        #t=threading.Thread(target=run, args=(i,))
        #t.start()
    t1 = threading.Thread(target=run, args=(1,))
    t1.start()
    t2 = threading.Thread(target=run, args=(2,))
    t2.start()

事件

1.python事件Event原理

事件event中有一个全局内置标志Flag,值为 True 或者False。使用wait()函数的线程会处于阻塞状态,此时Flag指为False,直到有其他线程调用set()函数让全局标志Flag置为True,其阻塞的线程立刻恢复运行,还可以用isSet()函数检查当前的Flag状态.

2.python事件Event相关函数介绍

set() — 全局内置标志Flag,将标志Flag 设置为 True,通知在等待状态(wait)的线程恢复运行;

isSet() — 获取标志Flag当前状态,返回True 或者 False;

wait() — 一旦调用,线程将会处于阻塞状态,直到等待其他线程调用set()函数恢复运行;

clear() — 将标志设置为False;
例如:

import threading
import time

def car():
    while True:
        if event.is_set():
            print("小车行驶")
        else:
            print("小车停止")
            event.wait()
def set_event():
    while True:
        event.set()
        time.sleep(1)
        event.clear()
        time.sleep(1)

if __name__ == '__main__':
    event = threading.Event()
    car1 = threading.Thread(target=car)
    car1.start()
    set_e = threading.Thread(target=set_event)
    set_e.start()

而对于本次的作业:使用类继承的方式,实现信号量、事件功能操作。具体案例:第一个
线程中获取当前时间,判断当前时间3秒之后,触发“事件” 对象。在另
一个线程中,作为数学考试结束的判断变量,否则一直处于考试中,并打
印。

import threading  # 导入threading模块
import time  # 导入time模块
import datetime  # 导入datetime模块


class Time(threading.Thread):  # 创建多线程的第一个类
    def __init__(self):  # 初始化方法
        super(Time, self).__init__()  # 继承父类方法

    def run(self):  # 重写父类方法
        print(datetime.datetime.now())  # 输出当前的年月日时分秒
        event.set()  # 设置事件


class MathExam(threading.Thread):  # 创建类
    def __init__(self):  # 初始化方法
        super(MathExam, self).__init__()  # 继承父类方法

    def run(self):  # 重写父类方法
        while True:
            time.sleep(3)  # 时间延迟3秒
            if event.is_set():  # 如果事件设定的话
                print("数学考试结束")  # 打印数学考试结束
                break  # 结束循环
            else:  # 否则的话
                print("考试中")  # 打印考试


if __name__ == "__main__":
    event = threading.Event()  # 创建事件

    t1 = Time()  # 实例化对象
    t1.start()  # 开始执行线程
    t2 = MathExam()  # 实例化对象
    t2.start()  # 开始执行线程
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值