Python語言中的協程(生產者-消費者舉例)
阿新 • • 發佈:2019-02-17
協程又被稱為微執行緒,它的特點是不需要進行執行緒的切換,因為整個程式的執行過程中,只有一個執行緒.沒有執行緒切換的開銷,和多執行緒相比較,執行緒數量越多,協程的效能就越高.它子程式的執行是由程式自身控制.又由於只存在一個執行緒,所以不存在什麼變數共享等衝突問題,也不存在鎖機制,更不會出現死鎖的情況.這樣一來,執行效率就比多執行緒高的多.為了有效利用多核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返回引數到生產者,生產者繼續生產,消費者子程式等待傳來引數,以此迴圈往復,直到生產者停止生產...