0
点赞
收藏
分享

微信扫一扫

Python第四次高级培训笔记

前行的跋涉者 2022-01-09 阅读 73

信号量:

信号量是由操作系统管理的一种抽象数据类型,用于在多线程中同步对共享资源的使用。本质上说,信号量是一个内部数据,用于标明当前的共享资源可以有多少并发读取。

threading模块里的Semaphore类实现了信号量对象,可用于控制获取资源的线程数量。所具有的acquire()和release()方法,可以用with语句的上下文管理器。当进入时,将调用acquire()方法,当退出时,将调用release()。

作用及应用:

主要用在数据库应用中,比如连接数据库的连接,限制同时连接的数量,如数据库连接池。
 

如上图所示,定义一个run方法,其中参数n表示输出的线程,用x来控制输出线程的延长时间,其中semaphore=threading,Seamphore(5),数字五来控制每次输出的线程的个数不能超过5

条件变量:

Python 提供的 Condition 对象提供了对复杂线程同步问题的支持。 Condition 被称为条件变量,除了提供与 Lock 类似的 acquire 和 release 方法外,还提供了 wait 和 notify 方法。

构造方法:

import threading
# 可传入一个互斥锁或者可重入锁
cond = threading.Condition()

实例方法:

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

从网上找的一个案例帮助理解: 

生产者与消费者模式,以吃火锅为例:一盘老肉片有10块肉,吃完了又重新往锅里加….

生产者:往锅里加老肉片,每次加一盘(10块);

消费者:吃煮熟的肉片,mei吃一片,肉片数量减一,吃完为止;

# 导入线程模块
import threading
import time
 
# 创建条件变量condition
con = threading.Condition()
meat_num = 0
 
def thread_consumers():
 # 条件变量condition 线程上锁
 con.acquire()
 
 # 全局变量声明关键字 global
 global meat_num
 meat_num = 0
 
 # 等待肉片下锅煮熟
 con.wait()
 while True:
 print("我来一块肉片...")
 meat_num -= 1
 print("剩余肉片数量:%d"%meat_num)
 time.sleep(0.5)
 if meat_num == 0:
 # 肉片吃光了,通知老板添加肉片
 print("老板,再来一份老肉片...")
 con.notify()
 # 肉片吃光了,等待肉片
 con.wait()
 
 # 条件变量condition 线程释放锁
 con.release()
 
 
def thread_producer():
 # 条件变量condition 线程上锁
 con.acquire()
 # 全局变量声明关键字 global
 global meat_num
 
 # 肉片熟了,可以开始吃了
 meat_num = 10
 print("肉片熟了,可以开始吃了...")
 con.notify()
 while True:
 # 阻塞函数,等待肉片吃完的通知
 con.wait()
 meat_num = 10
 # 添加肉片完成,可以继续开吃
 print("添加肉片成功!当前肉片数量:%d"%meat_num)
 time.sleep(1)
 con.notify()
 
 con.release()
 
 
if __name__ == "__main__":
 # 创建并初始化线程
 t1 = threading.Thread(target=thread_producer)
 t2 = threading.Thread(target=thread_consumers)
 
 # 启动线程 -- 注意线程启动顺序,启动顺序很重要
 t2.start()
 t1.start()
 
 # 阻塞主线程,等待子线程结束
 t1.join()
 t2.join()
 
 print("程序结束!")

 事件:

Event(事件):事件处理的机制:全局定义了一个内置标志Flag,如果Flag值为 False,那么当程序执行 event.wait方法时就会阻塞,如果Flag值为True,那么event.wait 方法时便不再阻塞。

Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。

Event()

  • set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态。

  • clear(): 将标志设为False。

  • wait(timeout): 如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()。

  • isSet(): 获取内置标志状态,返回True或False。

案例:

小伙伴a和b准备就绪,当收到通知event.set()的时候,会执行a和b线程

# coding:utf-8

import threading
import time

event = threading.Event()


def chihuoguo(name):
    # 等待事件,进入等待阻塞状态
    print '%s 已经启动' % threading.currentThread().getName()
    print '小伙伴 %s 已经进入就餐状态!'%name
    time.sleep(1)
    event.wait()
    # 收到事件后进入运行状态
    print '%s 收到通知了.' % threading.currentThread().getName()
    print '小伙伴 %s 开始吃咯!'%name

# 设置线程组
threads = []

# 创建新线程
thread1 = threading.Thread(target=chihuoguo, args=("a", ))
thread2 = threading.Thread(target=chihuoguo, args=("b", ))

# 添加到线程组
threads.append(thread1)
threads.append(thread2)

# 开启线程
for thread in threads:
    thread.start()

time.sleep(0.1)
# 发送事件通知
print '主线程通知小伙伴开吃咯!'
event.set()

运行结果:

Thread-1 已经启动
小伙伴 a 已经进入就餐状态!
Thread-2 已经启动
小伙伴 b 已经进入就餐状态!
主线程通知小伙伴开吃咯!
Thread-1 收到通知了.
小伙伴 a 开始吃咯!
Thread-2 收到通知了.
小伙伴 b 开始吃咯!

 

举报

相关推荐

网页前端第四次培训

第四次Pr笔记

HTML第四次笔记

python第四次作业

第四次作业

0 条评论