前言
概念
什麼是協程,可以參考廖雪峯老師的博客,下面的截圖來自於老師的博客。簡單說就是,函數調用執行過程中,轉而去執行其他函數,在適當的時候再返回來接着執行,是單線程的調用,卻感覺有二個線程併發執行。
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
這個例子就不進行分析了,我感覺結合上面的基礎,理解起來應該不難。
#參考文章