Python多線程-Event(事件對象)


Event

事件對象管理一個內部標志,通過set()方法將其設置為True,並使用clear()方法將其設置為Falsewait()方法阻塞,直到標志為True。該標志初始為False

方法:
is_set()
當且僅當內部標志為True時返回True

set()
將內部標志設置為True。所有等待它成為True的線程都被喚醒。當標志保持在True的狀態時,線程調用wait()是不會阻塞的。

clear()
將內部標志重置為False。隨后,調用wait()的線程將阻塞,直到另一個線程調用set()將內部標志重新設置為True

wait(timeout=None)
阻塞直到內部標志為真。如果內部標志在wait()方法調用時為True,則立即返回。否則,則阻塞,直到另一個線程調用set()將標志設置為True,或發生超時。
該方法總是返回True,除非設置了timeout並發生超時。

生產者與消費之--Event版

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


event = threading.Event()
goods = queue.Queue(5)
num = 0


class Producer(threading.Thread):
    def run(self):
        global num
        while True:
            if goods.empty():
                event.clear()
                for _ in range(5):
                    goods.put('商品-' + str(num))
                    print('生產了商品-{0}.'.format(str(num)))
                    num += 1
                    time.sleep(1)
                event.set()


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

    def run(self):
        while self.money:
            event.wait()
            self.money -= 1
            print('{0} 買了一個{1}.'.format(
                threading.current_thread().name, goods.get()))
            time.sleep(1)
        print('{0}沒錢了,回家.'.format(threading.current_thread().name))


if __name__ == '__main__':
    p = Producer(daemon=True)
    c1 = Customer(name='Alice')
    c2 = Customer(name='Bob')
    c2.start()
    p.start()
    c1.start()
    c1.join()
    c2.join()

運行結果:

生產了商品-0.
生產了商品-1.
生產了商品-2.
生產了商品-3.
生產了商品-4.
Alice 買了一個商品-0.
Bob 買了一個商品-1.
Alice 買了一個商品-2.
Bob 買了一個商品-3.
Alice 買了一個商品-4.
生產了商品-5.
生產了商品-6.
生產了商品-7.
生產了商品-8.
生產了商品-9.
Alice 買了一個商品-5.
Bob 買了一個商品-6.
Alice 買了一個商品-7.
Bob 買了一個商品-8.
生產了商品-10.
Alice 買了一個商品-9.
生產了商品-11.
生產了商品-12.
生產了商品-13.
生產了商品-14.
Alice 買了一個商品-10.
Bob 買了一個商品-11.
Alice沒錢了,回家.
Bob 買了一個商品-12.
Bob 買了一個商品-13.
Bob沒錢了,回家.

這里會出現一種特殊情況,當消費者線程較多時會大量出現:

生產了商品-0.
生產了商品-1.
生產了商品-2.
生產了商品-3.
生產了商品-4.
Bob 買了一個商品-0.
Alice 買了一個商品-1.
Bob 買了一個商品-2.
Alice 買了一個商品-3.
Bob 買了一個商品-4.
生產了商品-5.					# !!!!!
Alice 買了一個商品-5.			    # !!!!!
生產了商品-6.
生產了商品-7.
生產了商品-8.
生產了商品-9.
Bob 買了一個商品-6.
Alice 買了一個商品-7.
Alice 買了一個商品-8.
Bob 買了一個商品-9.
生產了商品-10.
生產了商品-11.
生產了商品-12.
生產了商品-13.
生產了商品-14.
Alice 買了一個商品-10.
Bob 買了一個商品-11.
Bob 買了一個商品-12.
Alice 買了一個商品-13.
Bob沒錢了,回家.
Alice沒錢了,回家.

這是因為生產者在輪詢檢查商品是否為空會有很小的延遲,在這個延遲中有消費者線程正好跑過了wait()方法,而阻塞在了商品獲取這里(商品使用了隊列,隊列是線程安全的,當隊列為空時,get()方法會阻塞),所以當生產者開始執行的時候,這個消費者因為商品隊列里有數據就被立即喚醒了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM