Python並行程式設計(五):多執行緒同步之event(事件)實現簡易的生產者-消費者模型

若數發表於2019-04-12

什麼是事件?

事件在內部管理了一個標誌Flag,如果Flag值為 False,那麼執行緒在執行event.wait方法時就會阻塞等值直到Flag值為True,該執行緒便會順利執行,而Flag的值是通過event.set()event.clear()設定的:

  • set(): 將標誌設為True,並通知所有處於等待阻塞狀態的執行緒恢復執行狀態。

  • clear(): 將標誌設為False

  • wait(timeout): 如果標誌為True將立即返回,否則阻塞執行緒至等待阻塞狀態,等待其他執行緒呼叫set()

  • isSet(): 獲取內建標誌狀態,返回TrueFalse

而Event其實就是一個簡化版的 Condition。Event沒有鎖,無法使執行緒進入同步阻塞狀態,所以當個多個執行緒處於wait狀態時,一旦標誌位Flag變為真時,這些執行緒便會 “同時” (GIL鎖的原因,假裝在同時執行)執行。

簡單的生產者-消費者模型

通過事件,我們也可以實現一個簡單的生產者-消費者模型:


import threading
import random
import time

# 假定商品序號
goods = 0

# 定義一個事件
event = threading.Event()

def consumer():

    time.sleep(0.5)
    print(threading.currentThread().getName() + ' consumer is wait for goods.')

    # 等待事件,進入阻塞狀態
    event.wait()

    print(threading.currentThread().getName() + ' consumer gets the goods: {}\n'.format(goods))

def producer():
    global goods
    time.sleep(1)
    goods = random.randint(1, 11)
    print('producer makes the goods: {}\n'.format(goods))
    time.sleep(1)
    # Flag --> True
    event.set()

if __name__ == "__main__":
    thread_consumer1 = threading.Thread(target=consumer) 
    thread_consumer2 = threading.Thread(target=consumer) 
    thread_producer = threading.Thread(target=producer) 

    thread_consumer1.start()
    thread_consumer2.start()
    thread_producer.start()

    thread_consumer1.join()
    thread_consumer2.join()
    thread_producer.join()

    print('consumer-producer example end.')

複製程式碼

執行截圖如下:

執行結果

我們可以看到,兩個消費者都在阻塞等待商品的生產,而一旦生產者通知商品生產成功(event.set() --> Flag=True),消費者們便都會得到該商品,這樣看來,event 看似就是condition的簡化版本,只是沒了鎖,執行緒們不能同步阻塞對共享資源的訪問。

相關文章