1. 程式人生 > >Python語言中的協程(生產者-消費者舉例)

Python語言中的協程(生產者-消費者舉例)

協程又被稱為微執行緒,它的特點是不需要進行執行緒的切換,因為整個程式的執行過程中,只有一個執行緒.沒有執行緒切換的開銷,和多執行緒相比較,執行緒數量越多,協程的效能就越高.它子程式的執行是由程式自身控制.又由於只存在一個執行緒,所以不存在什麼變數共享等衝突問題,也不存在鎖機制,更不會出現死鎖的情況.這樣一來,執行效率就比多執行緒高的多.為了有效利用多核CPU,我們可以用程序+協程,既充分利用多核,又充分發揮協程的高效率,可獲得極高的效能。
看例子:

傳統的生產者-消費者模型是一個執行緒寫訊息,一個執行緒取訊息,通過鎖機制控制佇列和等待,但一不小心就可能死鎖。

如果改用協程,生產者生產訊息後,直接通過yield跳轉到消費者開始執行,待消費者執行完畢後,切換回生產者繼續生產,效率極高:

# 注意 變成generator的函式,在首次呼叫的時候執行,遇到yield語句返回,再次執行時從上次返回的yield語句處繼續執行
def consumer():
    r = ''
    print('lalalalalaal') # 只有第一次會執行(啟動生成器), 之後再呼叫生成器就會從yield處執行
    while True:
        n = yield r # 再次執行時從這裡的yield繼續執行, 將把produce傳入的引數 n 賦給區域性變數 n . 下輪迴圈再次遇到yield就會就將 r 返回給produce函式
        # 所以Python的yield不但可以返回一個值,它還可以接收呼叫者發出的引數
print('xxxxxlalalalalaal') # 由於生成器在啟動的時候遇到上面的yield就返回了, 所以第一次不會執行這條語句. 之後每次都會被執行 if not n: return print('[CONSUMER] Consuming %s...' % n) r = '200 OK' # 因為yield r 所以這個r會在下一次迴圈被返回給produce函式 a = 'fake 200 OK' # 返回的值與a無關 def produce(c): c.send(None
) print('babababab') n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) # # 獲取生成器consumer中由yield語句返回的下一個值 print('[PRODUCER] Consumer return: %s' % r) c.close() c = consumer() # 並不會啟動生成器, 只是將c變為一個生成器 print('AaAaAaAaAa') # AaAaAaAaAa produce(c) # => # AaAaAaAaAa # lalalalalaal # babababab # [PRODUCER] Producing 1... # xxxxxlalalalalaal # [CONSUMER] Consuming 1... # [PRODUCER] Consumer return: 200 OK # [PRODUCER] Producing 2... # xxxxxlalalalalaal # [CONSUMER] Consuming 2... # [PRODUCER] Consumer return: 200 OK # [PRODUCER] Producing 3... # xxxxxlalalalalaal # [CONSUMER] Consuming 3... # [PRODUCER] Consumer return: 200 OK # [PRODUCER] Producing 4... # xxxxxlalalalalaal # [CONSUMER] Consuming 4... # [PRODUCER] Consumer return: 200 OK # [PRODUCER] Producing 5... # xxxxxlalalalalaal # [CONSUMER] Consuming 5... # [PRODUCER] Consumer return: 200 OK

    生成器generator這裡面的yield不但可以返回一個值,它還可以接收呼叫者發出的引數.首先等待生產者發出send()呼叫的引數,執行子程式,再通過yield返回引數到生產者,生產者繼續生產,消費者子程式等待傳來引數,以此迴圈往復,直到生產者停止生產...