在學習非同步io,會涉及到協程,最簡單的協程,可以用yield來模擬,最初學習yield的時候就沒搞太明白,今天看了些部落格,終於搞得懂了。
下面給出乙個作者的總結的知識點,讓我理解了。謝謝
主要的掌握
1.通常的for...in...迴圈中,in後面是乙個陣列,這個陣列就是乙個可迭代物件,類似的還有鍊錶,字串,檔案。它可以是mylist = [1, 2, 3],也可以是mylist = [x*x for x in range(3)]。
它的缺陷是所有資料都在記憶體中,如果有海量資料的話將會非常耗記憶體。
2.生成器是可以迭代的,但只可以讀取它一次。因為用的時候才生成。比如 mygenerator = (x*x for x in range(3)),注意這裡用到了(),它就不是陣列,而上面的例子是。
3.我理解的生成器(generator)能夠迭代的關鍵是它有乙個next()方法,工作原理就是通過重複呼叫next()方法,直到捕獲乙個異常。可以用上面的mygenerator測試。
4.帶有 yield 的函式不再是乙個普通函式,而是乙個生成器generator,可用於迭代,工作原理同上。
5.yield 是乙個類似 return 的關鍵字,迭代一次遇到yield時就返回yield後面的值。重點是:下一次迭代時,從上一次迭代遇到的yield後面的**開始執行。
6.簡要理解:yield就是 return 返回乙個值,並且記住這個返回的位置,下次迭代就從這個位置後開始。
7.帶有yield的函式不僅僅只用於for迴圈中,而且可用於某個函式的引數,只要這個函式的引數允許迭代引數。比如array.extend函式,它的原型是array.extend(iterable)。
8.send(msg)與next()的區別在於send可以傳遞引數給yield表示式,這時傳遞的引數會作為yield表示式的值(這裡應該理解到yield表示式,它是乙個表示式,而不僅僅yield產生乙個值),而yield的引數是返回給呼叫者的值。——換句話說,就是send可以強行修改上乙個yield表示式值。比如函式中有乙個yield賦值,a = yield 5,第一次迭代到這裡會返回5,a還沒有賦值。第二次迭代時,使用.send(10),那麼,就是強行修改yield 5表示式的值為10,本來是5的,那麼a=10
9.send(msg)與next()都有返回值,它們的返回值是當前迭代遇到yield時,yield後面表示式的值,其實就是當前迭代中yield後面的引數。
10.第一次呼叫時必須先next()或send(none),否則會報錯,send後之所以為none是因為這時候沒有上乙個yield(根據第8條)。可以認為,next()等同於send(none)。
#encoding:utf-8
def gener():
print "1"
x=yield "hello"
print "2","x=",x
y=5+(yield x)
print "3","y=",y
g=gener()
print g.next()#g.send(none)
'''這裡第一次呼叫時的兩種方法
輸出:1
hello #程式到yield就結束,下次呼叫時從斷開處繼續(這個特點會用在協程,非同步io,併發技術中)
'''print g.send(5)
'''繼上一次斷處執行print "2","x=",x y=5+(yield x)
由於send(5),那麼上一次yield表示式的值就位5,所以x=5
然後執行到yield x,則輸出yield後面的引數5
'''print g.send(2)
'''此時send(2),則上一次yield的表示式的值為2
則y=7
'''
二、使用yield實現協程
#coding=utf-8
__author__ = "zhangxiaozi"
#!/usr/bin/python
def consumer():
r = ''
while true:
n = yield r
#消費者通過yield表示式拿到訊息,再把yield的引數當做反饋結果反饋給生產者
if not n:
print("not n...")
return
print('[consumer] consuming %s...' % n)
r = '200 ok'
def produce(c):
f = c.send(none) #第一次f等於''
print('[producer] consumer first return: %s' % f)
n = 0
while n < 2:
n = n + 1
print('[producer] producing %s...' % n)
# 一旦產生東西就通過r = c.send(n)切換到消費者consumer執行
r = c.send(n)
print('[producer] consumer return: %s' % r)
c.close()
c = consumer()
produce(c)
程式結果:
[producer] consumer first return:
[producer] producing 1...
[consumer] consuming 1...
[producer] consumer return: 200 ok
[producer] producing 2...
[consumer] consuming 2...
[producer] consumer return: 200 ok
協程的說明:
注意到consumer函式是乙個generator,把乙個consumer傳入produce後:
首先呼叫c.send(none)啟動生成器;
然後,一旦生產了東西,通過c.send(n)切換到consumer執行;
consumer通過yield拿到訊息,處理,又通過yield把結果傳回;
produce拿到consumer處理的結果,繼續生產下一條訊息;
produce決定不生產了,通過c.close()關閉consumer,整個過程結束。
整個流程無鎖,由乙個執行緒執行,produce和consumer協作完成任務,所以稱為「協程」,而非執行緒的搶占式多工。
python yield 簡單理解
要想理解yield的概念,我們必須理解python中迭代器和生成器的概念與作用。1.迭代器 iterables python中可以直接作用於for迴圈的物件,比如 列表 元祖 字典 集合 字串等統稱為可迭代物件。迭代器是乙個實現了迭代器協議的物件,其可以呼叫next 方法得到下乙個結果,在結果末尾呼...
Python yield 與 send 實現協程
我們來看看在函式內部含有yield語句達到的效果。首先,我們來看看以下 def foo while true x yield print value x g foo g是乙個生成器 next g 程式執行到yield就停住了,等待下乙個next g.send 1 我們給yield傳送值1,然後這個值...
Python yield 的使用方法
帶有 yield 的函式在 python 中被稱之為 generator 生成器 使用 yield 可以大大簡化 yield 返回的是乙個generator物件,帶有 yield 的函式不再是乙個普通函式 def fab max n,a,b 0,0,1 while n fab 5 yield 的作用...