詳細說明Python中的Condition類(轉)

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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章