Python高级培训-第四次任务

学习视频链接: python语言爱好者的个人空间_哔哩哔哩_Bilibili  P70、P71、P72

信号量使用示例代码以及相关作用

信号量:是最古老的同步原语之一,是一个计数器。当资源释放时计数器就会递增,当资源申请时计数器就会递减。可以认为信号量就代表着资源是否可用

使用方法:

"""信号量"""
import threading
import time


def run(n,x):
    semaphore.acquire()  # 对该线程上锁
    print(n)
    time.sleep(x)  # 延迟1秒
    semaphore.release()  # 释放锁资源


if __name__ == '__main__':
    semaphore = threading.Semaphore(3)  # 将信号量实例化 括号里填写同时执行线程的个数
    for i in range(50):
        t = threading.Thread(target=run, args=(i, i))  # 调用threading.Thread()函数 target=方法名 args(参数, ) 如果没有参数,则threading.Thread(target=方法名)即可
        #args=(i, i) 中的参数对应 “target=方法名” 中方法的参数
        t.start()  # 线程执行语句
from threading import BoundedSemaphore
MAX = 3  # 资源最大值
semaphore = BoundedSemaphore(MAX)
print(semaphore._value)
semaphore.acquire()
print(semaphore._value)
semaphore.acquire()
print(semaphore._value)
semaphore.acquire()
print(semaphore._value)  # 0
semaphore.acquire(False)  # 没有资源可以申请,value的值为0,再次调用acquire方法会被阻塞。参数设为False则返回False不会被阻塞
print(semaphore._value)
semaphore.release()  #第一次释放
print(semaphore._value)
semaphore.release()
print(semaphore._value)
semaphore.release()  #第三次释放
print(semaphore._value)
semaphore.release()  #第四次释放,由于现在已经没有资源被占用所以会抛出异常

 

条件变量使用示例代码以及相关作用

条件变量:由于有些复杂问题互斥锁搞不定了。Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquirerelease方法外,还提供了waitnotify方法。

定义参考:[python] 线程间同步之条件变量Condition - 简书

"""条件变量"""
import threading
import time


def run(x):
    #lock.acquire()
    con.acquire()#使用条件变量
    print(f'线程{x}')
    con.notify() #结束上一个进程的等待状态 启动上一个进程
    print(f'线程{x}挂起')
    con.wait()#条件变量中的等待,线程中的等待函数为join()
    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()#条件变量中的等待,线程中的等待函数为join()
    time.sleep(1)
    print(f'线程{x}再次启动')
    con.notify()#程序运行完之后 启动上一个线程
    con.release()#资源释放
    #lock.release()



if __name__=='__main__':
    #lock = threading.Lock()
    con = threading.Condition()#条件变量
    # for i in range(10):
    #     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()

实例方法:

acquire([timeout])/release(): 调用关联的锁的相应方法。 
wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。
    使用前线程必须已获得锁定,否则将抛出异常。 
notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用
    acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会
    释放锁定。使用前线程必须已获得锁定,否则将抛出异常。 
notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池
    尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

事件实例代码及其相关作用

同进程的一样,线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其 他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用threading库中的Event对象。 对象包含一个可由线程设置的信号标志,它允许线程等待某些事件的发生。在 初始情况下,Event对象中的信号标志被设置为假。如果有线程等待一个Event对象, 而这个Event对象的标志为假,那么这个线程将会被一直阻塞直至该标志为真。一个线程如果将一个Event对象的信号标志设置为真,它将唤醒所有等待这个Event对象的线程。如果一个线程等待一个已经被设置为真的Event对象,那么它将忽略这个事件, 继续执行。

"""事件"""
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(3)

if __name__ =='__main__':
    event = threading.Event() #创建事件
    car1 = threading.Thread(target=car)
    car1.start()
    set_e = threading.Thread(target=set_event)
    set_e.start()

Event的几种方法: 

threading.Event(): 创建事件

event.isSet():返回event的状态值;

event.wait():如果 event.isSet()==False将阻塞线程;

event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;

event.clear():恢复event的状态值为False。

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

import threading
import time

def shijian():
    while True:
        day1=time.strftime("%Y %m %d %H:%M:%S", time.localtime())# 获取 格式化成2016-03-20 11:45:39形式 的本地时间 并赋值给day1
        day11=time.mktime(time.strptime(day1,"%Y %m %d %H:%M:%S"))# 将格式字符串转换为时间戳 并赋值给day11
        time.sleep(3)#延迟3秒
        day2=time.strftime("%Y %m %d %H:%M:%S", time.localtime())# 获取 格式化成2016-03-20 11:45:39形式 的本地时间 并赋值给day2
        day22 = time.mktime(time.strptime(day2, "%Y %m %d %H:%M:%S"))# 将格式字符串转换为时间戳 并赋值给day22
        day=day22-day11 #将时间差赋值给day
        print(day)#输出day

        if day==3: #如果时间间隔为3秒
            set_event() # 创建事件
            print("事件1触发成功")
            break #跳出循环
        else:
            print("事件1触发失败")


def kaoshi():
    while True:
        time.sleep(1) #延时1秒
        if event.is_set():#如果设置了事件
            print("考试结束")
            break  #跳出循环
        else:
            print("正在考试中")

def set_event():
    while True:
        event.set()#设置事件
        time.sleep(1) #延迟1秒
        if event.is_set():  # 如果间隔事件为3秒
            print("事件2触发成功")
            break #跳出循环
        else:
            print("事件2触发失败")
        # event.clear() #把所设置的事件清除
        # time.sleep(3)


# 用类来创建多线程
#创建类 继承自threading.Thread
class MyThread(threading.Thread):
    def __init__(self): #初始化 并传递参数
        super(MyThread, self).__init__() #继承自父类的初始化

    # 启动线程的函数 函数名必须是run
    def run(self):
        shijian() #进入shijian()函数


# 用类来创建多线程
#创建类 继承自threading.Thread
class mythread(threading.Thread):
    def __init__(self): #初始化 并传递参数
        super(mythread, self).__init__() #继承自父类的初始化

    # 启动线程的函数 函数名必须是run
    def run(self):
           kaoshi() #进入kaoshi()函数



#程序主入口
if __name__ == '__main__':
    event = threading.Event()  # 创建事件
    # semaphore = threading.Semaphore(2)  # 将信号量实例化 括号里填写同时执行线程的个数
    #调用类多线程
    r1=MyThread() #实例化所创建的类
    r1.start() # 启动多线程
    r2=mythread() #实例化所创建的类
    r2.start() # 启动多线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值