1. 程式人生 > >python執行緒條件變數Condition(31)

python執行緒條件變數Condition(31)

     對於執行緒與執行緒之間的互動我們在前面的文章已經介紹了 python 互斥鎖Lock / python事件Event , 今天繼續介紹一種執行緒互動方式 – 執行緒條件變數Condition.

 

 

一.執行緒條件變數Condition相關函式介紹

    acquire() —  執行緒鎖,注意執行緒條件變數Condition中的所有相關函式使用必須在acquire() /release() 內部操作;

    release() — 釋放鎖,注意執行緒條件變數Condition中的所有相關函式使用必須在acquire() /release() 內部操作;

    wait(timeout) —  執行緒掛起(阻塞狀態),直到收到一個notify通知或者超時才會被喚醒繼續執行(超時引數預設不設定,可選填,型別是浮點數,單位是秒)。wait()必須在已獲得Lock前提下才能呼叫,否則會觸發RuntimeError;

    notify(n=1) —  通知其他執行緒,那些掛起的執行緒接到這個通知之後會開始執行,預設引數,預設是通知一個正等待通知的執行緒,最多則喚醒n個等待的執行緒。notify()必須在已獲得Lock前提下才能呼叫,否則會觸發RuntimeError,notify()不會主動釋放Lock;

    notifyAll() —  如果wait狀態執行緒比較多,notifyAll的作用就是通知所有執行緒;

 

 

 

二.執行緒條件變數Condition原理

    在前面的文章已經介紹過互斥鎖,主要作用是並行訪問共享資源時,保護共享資源,防止出現髒資料。python 條件變數Condition也需要關聯互斥鎖,同時Condition自身提供了wait/notify/notifyAll方法,用於阻塞/通知其他並行執行緒,可以訪問共享資源了。可以這麼理解,Condition提供了一種多執行緒通訊機制,假如執行緒1需要資料,那麼執行緒1就阻塞等待,這時執行緒2就去製造資料,執行緒2製造好資料後,通知執行緒1可以去取資料了,然後執行緒1去獲取資料。

三.執行緒條件變數Condition使用

    案例一:成語接龍

# !usr/bin/env python
# -*- coding:utf-8 _*-
"""
@Author:何以解憂
@Blog(個人部落格地址): shuopython.com
@WeChat Official Account(微信公眾號):猿說python
@Github:www.github.com
 
@File:python_.py
@Time:2019/10/21 21:25
 
@Motto:不積跬步無以至千里,不積小流無以成江海,程式人生的精彩需要堅持不懈地積累!
"""
 
# 匯入執行緒模組
import threading
 
# 建立條件變數condition
con = threading.Condition()
 
def thread_one(name):
    # 條件變數condition 執行緒上鎖
    con.acquire()
 
    print("{}:成語接龍準備好了嗎".format(name))
    # 喚醒正在等待(wait)的執行緒
    con.notify()
 
    # 等待對方迴應訊息,使用wait阻塞執行緒,等待對方通過notify喚醒本執行緒
    con.wait()
    print("{}:一乾二淨".format(name))
    # 喚醒對方
    con.notify()
 
    # 等待訊息答應
    con.wait()
    print("{}:一天就知道看抖音美女,給你來個簡單點的,來了:毛手毛腳".format(name))
    # 喚醒對方
    con.notify()
 
    # 等待訊息答應
    con.wait()
    print("{}:喲喲喲,不錯不錯!".format(name))
    # 喚醒對方
    con.notify()
 
    # 條件變數condition 執行緒釋放鎖
    con.release()
 
def thread_two(name):
    # 條件變數condition 執行緒上鎖
    con.acquire()
 
    # wait阻塞狀態,等待其他執行緒通過notify喚醒本執行緒
    con.wait()
    print("{}:準備好了~開始吧!".format(name))
    # 喚醒對方
    con.notify()
 
    # 等待訊息答應
    con.wait()
    print("{}:淨你妹啊,沒法接...來個簡單點的...".format(name))
    # 喚醒對方
    con.notify()
 
    # 等待訊息答應
    con.wait()
    print("{}:嘿,這個我知道:腳踏實地".format(name))
    # 喚醒對方
    con.notify()
 
    con.release()
 
if __name__ == "__main__":
 
    # 建立並初始化執行緒
    t1 = threading.Thread(target=thread_one,args=("A"))
    t2 = threading.Thread(target=thread_two,args=("B"))
 
    # 啟動執行緒 -- 注意執行緒啟動順序,啟動順序很重要
    t2.start()
    t1.start()
 
    # 阻塞主執行緒,等待子執行緒結束
    t1.join()
    t2.join()
 
 
    print("程式結束!")

 

輸出結果:

 
A:成語接龍準備好了嗎
B:準備好了~開始吧!
A:一乾二淨
B:淨你妹啊,沒法接...來個簡單點的...
A:一天就知道看抖音美女,給你來個簡單點的,來了:毛手毛腳
B:嘿,這個我知道:腳踏實地
A:喲喲喲,不錯不錯!
程式結束!

 

    案例二:生產者與消費者模式,以吃火鍋為例:一盤老肉片有10塊肉,吃完了又重新往鍋里加….

    生產者:往鍋里加老肉片,每次加一盤(10塊);

    消費者:吃煮熟的肉片,沒吃一片,肉片數量減一,吃完為止;

# 匯入執行緒模組
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("程式結束!")

 

    輸出結果:

肉片熟了,可以開始吃了...
我來一塊肉片...
剩餘肉片數量:9
我來一塊肉片...
剩餘肉片數量:8
我來一塊肉片...
剩餘肉片數量:7
我來一塊肉片...
剩餘肉片數量:6
我來一塊肉片...
剩餘肉片數量:5
我來一塊肉片...
剩餘肉片數量:4
我來一塊肉片...
剩餘肉片數量:3
我來一塊肉片...
剩餘肉片數量:2
我來一塊肉片...
剩餘肉片數量:1
我來一塊肉片...
剩餘肉片數量:0
老闆,再來一份老肉片...
新增肉片成功!當前肉片數量:10
我來一塊肉片...
剩餘肉片數量:9
我來一塊肉片...
剩餘肉片數量:8
我來一塊肉片...
剩餘肉片數量:7
.............

 

注意:

    1.全域性變數要宣告關鍵字 global;

    2.注意執行緒的啟動順序,這個很重要;

 

四.重點總結

    注意執行緒互斥鎖Lock/執行緒事件Event/執行緒條件變數Condition三者的區別,場景不同,使用方式也不同,前兩者一般可以作為簡單的執行緒互動,執行緒條件變數Condition可以用於比較複雜的執行緒互動!

 

猜你喜歡:

    1.python執行緒建立和引數傳遞

    2.python執行緒互斥鎖Lock

    3.python執行緒事件Event

    4.python return邏輯判斷表示式

 

    轉載請註明:猿說Python » python條件變數Condition

 

技術交流、商務合作請直接聯絡博主 掃碼或搜尋:猿說python 猿說python 微信公眾號 掃一掃關