python多線程--Condition(條件對象)

Condition

class threading.Condition(lock=None
這個類實現條件變量對象。條件變量容許一個或多個線程等待,知道它們被另外一個線程喚醒。
若是給出了lock參數而不是None,則它必須是LcokRLock對象,並以它做爲底層的鎖。不然將默認建立一個RLock對象。
Condition遵循上下文管理協議。
方法:
acquire(*args)
獲取鎖。這個方法調用底層鎖的相應方法。python

release()
釋放鎖。這個方法調用底層鎖的相應方法。併發

wait(timeout=None)
線程掛起,等待被喚醒(其餘線程的notify方法)或者發生超時。調用該方法的線程必須先得到鎖,不然引起RuntimeError
該方法會釋放底層鎖,而後阻塞,直到它被另外一個線程中的相同條件變量的notify()notify_all()方法喚醒,或者發生超時。一旦被喚醒或超時,它會從新獲取鎖並返回。
返回值爲True,若是給定timeout併發生超時,則返回Falseui

wait_for(predicate, timeout=None)
等待知道條件變量的返回值爲Truepredicate應該是一個返回值能夠解釋爲布爾值的可調用對象。能夠設置timeout以給定最大等待時間。
該方法能夠重複調用wait(),直到predicate的返回值解釋爲True,或發生超時。該方法的返回值就是predicate的最後一個返回值,若是發生超時,返回值爲False
若是忽略超時功能,該方法大體至關於:線程

while not predicate():
    con.wait()

它與wait()的規則相同:調用前必須先獲取鎖,阻塞時釋放鎖,並在被喚醒時從新獲取鎖並返回。code

notify(n=1)
默認狀況下,喚醒等待此條件變量的一個線程(若是有)。調用該方法的線程必須先得到鎖,不然引起RuntimeError
該方法最多喚醒n個等待中的線程,若是沒有線程在等待,它就是要給無動做的操做。
注意:要被喚醒的線程實際上不會立刻從wait()方法返回(喚醒),而是等到它從新獲取鎖。這是由於notify()並不會釋放鎖,須要線程自己來釋放(經過wait()或者release())orm

notify_all()
此方法相似於notify(),但喚醒的時全部等待的線程。對象

生產者與消費者 -- Condition版

場景:生產者一次性生產5個商品(生產過程當中不可購買),以後通知消費者搶購,當商品賣完後,由消費者通知生產者開始生產。utf-8

# -*- coding:utf-8 -*-
import threading
import time


num = 0
con = threading.Condition()


class Producer(threading.Thread):
    """生產者"""
    def run(self):
        global num
        # 獲取鎖
        con.acquire()
        while True:
            num += 1
            print('生產了1個,如今有{0}個'.format(num))
            time.sleep(1)
            if num >= 5:
                print('已達到5個,再也不生產')
                # 喚醒消費者
                con.notify()
                # 等待-釋放鎖;被喚醒-獲取鎖
                con.wait()
        # 釋放鎖
        con.release()


class Customer(threading.Thread):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.money = 7

    def run(self):
        global num
        while self.money > 0:
            # 因爲場景是多個消費者進行搶購,若是將獲取鎖操做放在循環外(如生產者),
            # 那麼一個消費者線程被喚醒時會鎖住整個循環,沒法實現另外一個消費者的搶購。
            # 在循環中添加一套"獲取鎖-釋放鎖",一個消費者購買完成後釋放鎖,其餘消費者
            # 就能夠獲取鎖來參與購買。
            con.acquire()
            if num <= 0:
                print('沒貨了,{0}通知生產者'.format(
                    threading.current_thread().name))
                con.notify()
                con.wait()
            self.money -= 1
            num -= 1
            print('{0}消費了1個, 剩餘{1}個'.format(
                threading.current_thread().name, num))
            con.release()
            time.sleep(1)
        print('{0}沒錢了-回老家'.format(threading.current_thread().name))


if __name__ == '__main__':
    p = Producer(daemon=True)
    c1 = Customer(name='Customer-1')
    c2 = Customer(name='Customer-2')
    p.start()
    c1.start()
    c2.start()
    c1.join()
    c2.join()

運行結果:it

生產了1個,如今有1個
生產了1個,如今有2個
生產了1個,如今有3個
生產了1個,如今有4個
生產了1個,如今有5個
已達到5個,再也不生產
Customer-1消費了1個, 剩餘4個
Customer-2消費了1個, 剩餘3個
Customer-1消費了1個, 剩餘2個
Customer-2消費了1個, 剩餘1個
Customer-1消費了1個, 剩餘0個
沒貨了,Customer-2通知生產者
生產了1個,如今有1個
生產了1個,如今有2個
生產了1個,如今有3個
生產了1個,如今有4個
生產了1個,如今有5個
已達到5個,再也不生產
Customer-1消費了1個, 剩餘4個
Customer-2消費了1個, 剩餘3個
Customer-1消費了1個, 剩餘2個
Customer-2消費了1個, 剩餘1個
Customer-1消費了1個, 剩餘0個
沒貨了,Customer-2通知生產者
生產了1個,如今有1個
生產了1個,如今有2個
生產了1個,如今有3個
生產了1個,如今有4個
生產了1個,如今有5個
已達到5個,再也不生產
Customer-1消費了1個, 剩餘4個
Customer-2消費了1個, 剩餘3個
Customer-2消費了1個, 剩餘2個
Customer-1消費了1個, 剩餘1個
Customer-1沒錢了-回老家
Customer-2消費了1個, 剩餘0個
沒貨了,Customer-2通知生產者
生產了1個,如今有1個
生產了1個,如今有2個
生產了1個,如今有3個
生產了1個,如今有4個
生產了1個,如今有5個
已達到5個,再也不生產
Customer-2消費了1個, 剩餘4個
Customer-2沒錢了-回老家
相關文章
相關標籤/搜索