详细说明Python中的Condition类(转)

发布时间 2023-07-18 18:10:01作者: 奋斗终生

add by zhj: 之前只知道在Queue的实现中使用了Condition对象,可以实现生产者消费者功能,但具体怎么使用Condition还是一知半解,看了这篇文章,终于懂了。很多事情往往一时看不明白,看得多了,某一天就突然明白了。

 

原文:https://blog.csdn.net/ckk727/article/details/99950843

作者:二十七º

网站:CSDN
 
  互斥锁Lock和RLock只能提供简单的加锁和释放锁等功能,它们的主要作用是在多线程访问共享数据时,保护共享数据,防止数据被脏读脏写,保证数据和关键代码的完整性。在此基础上,Python提供了Condition类,Condition类不仅自身依赖于Lock和RLock,即具有它们的阻塞特性,此外还提供了一些有利于线程通信,以及解决复杂线程同步问题的方法,它也被称作条件变量。
 

一、Condition类提供的方法

1. 构造方法:
__init__(self,lock=None)

1)从Condition类的构造方法可以看出,Condition类总是与一个锁相关联。在创建一个Condition类的同时就应该传入Condition类需要绑定的Lock对象;

2)另外,如果不指定lock参数,那么Python会自动创建一个与之绑定的Lock对象。

 

2. acquire方法

acquire(timeout)

调用Condition类关联的Lock/RLock的acquire()方法。

 

3. release方法

release()

调用Condition类关联的Lock/RLock的release()方法。

 

4. wait方法

wait(timeout)

1)线程挂起,直到收到一个notify通知或者等待时间超出timeout才会被唤醒;

2)注意:wait()必须在已获得Lock的前提下调用,否则会引起RuntimeError错误。

 

5. notify方法

notify(n=1)

1)唤醒在Condition的waiting池中的n(参数n可设置,默认为1)个正在等待的线程并通知它,受到通知的线程将自动调用acquire()方法尝试加锁;

2)如果waiting池中有多个线程,随机选择n个唤醒;

3)必须在已获得Lock的前提下调用,否则将引发错误。

 
6. notify_all方法
notify_all()

唤醒waiting池中的等待的所有线程并通知它们。

 

二、实例详解

生产者消费者问题

问题:

假设有一群生产者(Producer)和一群消费者(Consumer)通过一个市场来交互产品。生产者的”策略“是如果市场上剩余的产品少于500个,那么就生产50个产品放到市场上;而消费者的”策略“是如果市场上剩余产品的数量多于100个,那么就消费10个产品。

代码:

 

import threading
from time import sleep

#商品
product = 500
#条件变量
con = threading.Condition(threading.Lock())

#生产者类
#继承Thread类
class Producer(threading.Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name
    def run(self):
        global product
        while True:
            #如果获得了锁
            if con.acquire():
                #处理产品大于等于500和小于500的情况
                if product >= 500:
                    #如果大于等于500,Producer不需要额外操作,于是挂起
                    con.wait()
                else:
                    product += 50
                    message = self.name + " produced 50 products."
                    print(message)
                    #处理完成,发出通知告诉Consumer
                    con.notify()
                #释放锁
                con.release()
                sleep(1)
#消费者类
#继承Thread类
class Consumer(threading.Thread):
    def __init__(self,name):
        super().__init__()
        self.name = name
    def run(self):
        global product
        while True:
            #如果获得了锁
            if con.acquire():
                #处理product小于等于100和大于100的两种情况
                if product <= 100:
                    #如果小于等于100,Consumer不需要额外操作,于是挂起
                    con.wait()
                else:
                    product -= 10
                    message = self.name + " consumed 10 products."
                    print(message)
                    #处理完成,发出通知告诉Producer
                    con.notify()
                #释放锁
                con.release()
                sleep(1)
                
def main():
    #创建两个Producer
    for i in range(2):
        p = Producer('Producer-%d'%i)
        p.start()
    #创建三个Consumer
    for i in range(3):
        c = Consumer('Consumer-%d'%i)
        c.start()

if __name__ == '__main__':
    main()

 

运行结果:

Consumer-0 consumed 10 products.
Consumer-1 consumed 10 products.
Consumer-2 consumed 10 products.
Producer-0 produced 50 products.
Consumer-0 consumed 10 products.
Consumer-1 consumed 10 products.
Consumer-2 consumed 10 products.
Producer-0 produced 50 products.
Consumer-1 consumed 10 products.
Consumer-0 consumed 10 products.
Consumer-2 consumed 10 products.
Consumer-1 consumed 10 products.
......

 

 

 

互斥锁Lock和RLock只能提供简单的加锁和释放锁等功能,它们的主要作用是在多线程访问共享数据时,保护共享数据,防止数据被脏读脏写,保证数据和关键代码的完整性。在此基础上,Python提供了Condition类,Condition类不仅自身依赖于Lock和RLock,即具有它们的阻塞特性,此外还提供了一些有利于线程通信,以及解决复杂线程同步问题的方法,它也被称作条件变量。
一、Condition类提供的方法构造方法:
__init__(self,lock=None)11)从Condition类的构造方法可以看出,Condition类总是与一个锁相关联。在创建一个Condition类的同时就应该传入Condition类需要绑定的Lock对象;
2)另外,如果不指定lock参数,那么Python会自动创建一个与之绑定的Lock对象。
acquire(timeout)1调用Condition类关联的Lock/RLock的acquire()方法。
release()1调用Condition类关联的Lock/RLock的release()方法。
wait(timeout)11)线程挂起,直到收到一个notify通知或者等待时间超出timeout才会被唤醒;
2)注意:wait()必须在已获得Lock的前提下调用,否则会引起RuntimeError错误。
notify(n=1)11)唤醒在Condition的waiting池中的n(参数n可设置,默认为1)个正在等待的线程并通知它,受到通知的线程将自动调用acquire()方法尝试加锁;
2)如果waiting池中有多个线程,随机选择n个唤醒;
3)必须在已获得Lock的前提下调用,否则将引发错误。
notify_all()1唤醒waiting池中的等待的所有线程并通知它们。
二、实例详解生产者消费者问题
问题:
假设有一群生产者(Producer)和一群消费者(Consumer)通过一个市场来交互产品。生产者的”策略“是如果市场上剩余的产品少于500个,那么就生产50个产品放到市场上;而消费者的”策略“是如果市场上剩余产品的数量多于100个,那么就消费10个产品。
代码:
import threadingfrom time import sleep
#商品product = 500#条件变量con = threading.Condition(threading.Lock())
#生产者类#继承Thread类class Producer(threading.Thread):    def __init__(self,name):        super().__init__()        self.name = name    def run(self):        global product        while True:            #如果获得了锁            if con.acquire():                #处理产品大于等于500和小于500的情况                if product >= 500:                    #如果大于等于500,Producer不需要额外操作,于是挂起                    con.wait()                else:                    product += 50                    message = self.name + " produced 50 products."                    print(message)                    #处理完成,发出通知告诉Consumer                    con.notify()                #释放锁                con.release()                sleep(1)#消费者类#继承Thread类class Consumer(threading.Thread):    def __init__(self,name):        super().__init__()        self.name = name    def run(self):        global product        while True:            #如果获得了锁            if con.acquire():                #处理product小于等于100和大于100的两种情况                if product <= 100:                    #如果小于等于100,Consumer不需要额外操作,于是挂起                    con.wait()                else:                    product -= 10                    message = self.name + " consumed 10 products."                    print(message)                    #处理完成,发出通知告诉Producer                    con.notify()                #释放锁                con.release()                sleep(1)                def main():    #创建两个Producer    for i in range(2):        p = Producer('Producer-%d'%i)        p.start()    #创建三个Consumer    for i in range(3):        c = Consumer('Consumer-%d'%i)        c.start()
if __name__ == '__main__':    main()123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869运行结果:
Consumer-0 consumed 10 products.Consumer-1 consumed 10 products.Consumer-2 consumed 10 products.Producer-0 produced 50 products.Consumer-0 consumed 10 products.Consumer-1 consumed 10 products.Consumer-2 consumed 10 products.Producer-0 produced 50 products.Consumer-1 consumed 10 products.Consumer-0 consumed 10 products.Consumer-2 consumed 10 products.Consumer-1 consumed 10 products.......————————————————版权声明:本文为CSDN博主「二十七º」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/ckk727/article/details/99950843