理解python協程(消費者生產者demo+yield的使用)

前言

概念

什麼是協程,可以參考廖雪峯老師的博客,下面的截圖來自於老師的博客。簡單說就是,函數調用執行過程中,轉而去執行其他函數,在適當的時候再返回來接着執行,是單線程的調用,卻感覺有二個線程併發執行。
在這裏插入圖片描述

yield關鍵字

python中,如果函數使用yield關鍵字,那就是一個生成器(generator)函數。
比如下面代碼


>>> def a():
...     print('aaa')
...     p = yield '123'
...     print(p)
...     print('bbb')
...
>>> c =a()
>>> d = next(c)
aaa
>>> d
'123'
>>> d = next(c)
None
bbb
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>>

剖析:第一次調用next( c )的時候,相當於調用c.send(None)
爲啥這樣說,因爲我們知道,程序執行過程中,遇到yield關鍵字是會暫停的,然後當其他地方調用send或next的時候才被喚醒,同時可以拿到傳遞過來的值。
而第一次之前,我們的程序還沒有開始執行,所以它並沒有在yield那個地方等待。
也就說,第一次無法發送數據給yield。所以,此時使用c.send(None)或者next( c )結果是一樣的,目的不是爲了傳遞數據,而是啓動生成器。

剖析:代碼中使用yield來接收數據和返回數據
使用yield來接收數據這個比較好理解,比如yield可以接收到c.send(‘需要傳遞的數據’)裏面的數據。
通過上面的剖析,代碼中第一次next( c )實際上和c.send(None)一樣,而且代碼運行中,就只是print(‘aaa’)然後程序遇到yield就暫停了,第一次發送的None在第二次遇見yield之前(當然這裏沒有第二個yield),就打印出來了,可以細心看下上面代碼。

通過上面的二個剖析。我們發現yield的語句確實有點小小的不同,我們拿出一點來分析:

	p = yield '123'

上面這個代碼,當程序從執行send(next)代碼,然後執行它的時候,它會把攜帶的數據賦值給p
可以想象成

	p = 攜帶的數據

後面的‘123’就沒用處了。

當程序執行然後遇到yield即將要暫停的時候,上面的代碼可以想象成

	yield '返回的數據'

所以就這一句普通的**p = yield ‘123’**代碼,在不同的情景下面,需要不同的處理!!這個是關鍵所在,也就是大家常常被繞暈的原因(這東西也有在for循環中使用的場景)。

道高一丈

瞭解了上面的東西,就可以使用yield來弄一個生產者-消費者的小demo了,O(∩_∩)O哈哈~。
如下代碼:

def consumer():
    r = ''
    while True:
        n = yield r
        if not n: //這裏是爲了第一次調用next()的時候直接return的
            return
        print('[CONSUMER] Consuming %s...' % n)
        r = '200 OK'

def produce(c):
    c.send(None)
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()

c = consumer()
produce(c)

執行結果如下:

[PRODUCER] Producing 1...
[CONSUMER] Consuming 1...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 2...
[CONSUMER] Consuming 2...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 3...
[CONSUMER] Consuming 3...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 4...
[CONSUMER] Consuming 4...
[PRODUCER] Consumer return: 200 OK
[PRODUCER] Producing 5...
[CONSUMER] Consuming 5...
[PRODUCER] Consumer return: 200 OK

這個例子就不進行分析了,我感覺結合上面的基礎,理解起來應該不難。

#參考文章

  1. 廖雪峯官方網站-協程
  2. python之next和send用法詳解
  3. python3學習的github(start一波)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章