Python并行編程(四):多線程同步之condition(條件變量)實(shí)現(xiàn)帶有緩沖區(qū)的生產(chǎn)者-消費(fèi)者模型

什么是Condtion?

所謂condition條件變量,即這種機(jī)制是在滿足了特定的條件后,線程才可以訪問相關(guān)的數(shù)據(jù)。 這種同步機(jī)制就是一個(gè)線程等待特定的條件,另一個(gè)線程通知它條件已經(jīng)發(fā)生。一旦條件發(fā)生,該線程就會(huì)獲取鎖,從而獨(dú)占共享資源的訪問。
Condition包含以下部分:

  • c.acquire(args):獲取底層鎖。此方法將調(diào)用底層鎖上對(duì)應(yīng)的acquire(args)方法。
  • c.release():釋放底層鎖。此方法將調(diào)用底層鎖上對(duì)應(yīng)的release()方法
  • c.wait(timeout):等待直到獲取通知或出現(xiàn)超時(shí)為止。此方法在調(diào)用線程已經(jīng)獲取鎖之后調(diào)用。
    調(diào)用時(shí),將釋放底層鎖,而且線程將進(jìn)入睡眠狀態(tài),直到另一個(gè)線程在條件變量上執(zhí)行notify()或notify_all()方法將其喚醒為止。在線程被喚醒后,線程講重新獲取鎖,方法也會(huì)返回。timeout是浮點(diǎn)數(shù),單位為秒。
    如果超時(shí),線程將被喚醒,重新獲取鎖,而控制將被返回。
  • c.notify(n):?jiǎn)拘岩粋€(gè)或多個(gè)等待此條件變量的線程。此方法只會(huì)在調(diào)用線程已經(jīng)獲取鎖之后調(diào)用,
    而且如果沒有正在等待的線程,它就什么也不做。
    n指定要喚醒的線程數(shù)量,默認(rèn)為1.被喚醒的線程在它們重新獲取鎖之前不會(huì)從wait()調(diào)用返回。

c.notify_all():?jiǎn)拘阉械却藯l件的線程。
通俗的解釋:

Python提供的Condition對(duì)象提供了對(duì)復(fù)雜線程同步問題的支持。Condition被稱為條件變量,除了提供與Lock類似的 acquire和release方法外,還提供了wait和notify方法。線程首先acquire一個(gè)條件變量,然后判斷一些條件。如果條件不滿足則 wait;如果條件滿足,進(jìn)行一些處理改變條件后,通過notify方法通知其他線程,其他處于wait狀態(tài)的線程接到通知后會(huì)重新判斷條件。不斷的重復(fù) 這一過程,從而解決復(fù)雜的同步問題。
可以認(rèn)為Condition對(duì)象維護(hù)了一個(gè)鎖(Lock/RLock)和一個(gè)waiting池。線程通過acquire獲得Condition對(duì) 象,當(dāng)調(diào)用wait方法時(shí),線程會(huì)釋放Condition內(nèi)部的鎖并進(jìn)入blocked狀態(tài),同時(shí)在waiting池中記錄這個(gè)線程。當(dāng)調(diào)用notify 方法時(shí),Condition對(duì)象會(huì)從waiting池中挑選一個(gè)線程,通知其調(diào)用acquire方法嘗試取到鎖。
Condition對(duì)象的構(gòu)造函數(shù)可以接受一個(gè)Lock/RLock對(duì)象作為參數(shù),如果沒有指定,則Condition對(duì)象會(huì)在內(nèi)部自行創(chuàng)建一個(gè)RLock。

帶有緩沖區(qū)的生產(chǎn)者-消費(fèi)者模型

我們可以根據(jù)所謂的wait池構(gòu)建一個(gè)帶有緩沖區(qū)的生產(chǎn)者-消費(fèi)者模型,即緩沖區(qū)好比一個(gè)倉庫,生產(chǎn)者可以不斷生產(chǎn)商品知道倉庫裝滿,然后告知消費(fèi)者消費(fèi),而消費(fèi)者也可以判斷倉庫是否滿了告知生產(chǎn)者繼續(xù)生產(chǎn)商品:


import threading
import time

# 假設(shè)商品數(shù)量
goods = 0

condition = threading.Condition()


def consumer():
    global goods
    while True:
        condition.acquire()
        if goods <= 0:
            # 倉庫空了,即特定條件滿足了,通知生產(chǎn)者生產(chǎn)
            condition.notify()
            condition.wait()
        time.sleep(2)
        goods -= 1
        print('consume 1, left {}'.format(goods))
        time.sleep(2)

        condition.release()


def producer():
    global goods
    while True:
        condition.acquire()
        if goods >= 5:
            # 倉庫滿了,即特定條件滿足了,通知消費(fèi)者消費(fèi)
            condition.notify()
            condition.wait()

        time.sleep(2)
        goods += 1
        print('produce 1, already {}'.format(goods))
        time.sleep(2)

        condition.release()


if __name__ == '__main__':
    thread_consumer = threading.Thread(target=consumer)
    thread_producer = threading.Thread(target=producer)

    thread_consumer.start()
    thread_producer.start()

    thread_consumer.join()
    thread_producer.join()

    print('consumer-producer example end.')

運(yùn)行截圖如下:


運(yùn)行結(jié)果
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 【threading模塊詳解】 模塊基本方法 該模塊定了的方法如下:threading.active_count(...
    奕劍聽雨閱讀 1,154評(píng)論 0 0
  • 接著上節(jié) atomic,本節(jié)主要介紹condition_varible的內(nèi)容,練習(xí)代碼地址。本文參考http://...
    jorion閱讀 8,658評(píng)論 0 7
  • 線程 操作系統(tǒng)線程理論 線程概念的引入背景 進(jìn)程 之前我們已經(jīng)了解了操作系統(tǒng)中進(jìn)程的概念,程序并不能單獨(dú)運(yùn)行,只有...
    go以恒閱讀 1,800評(píng)論 0 6
  • 為什么需要條件變量 有了前面提到的互斥鎖,為什么還需要條件變量呢,當(dāng)然是由于有些復(fù)雜問題互斥鎖搞不定了。Pytho...
    StormZhu閱讀 9,704評(píng)論 8 18
  • ReentrantLock 介紹 一個(gè)可重入的互斥鎖,它具有與使用{synchronized}方法和語句訪問的隱式...
    tomas家的小撥浪鼓閱讀 4,262評(píng)論 1 4

友情鏈接更多精彩內(nèi)容