近几天学习了关于生成器与协程的相关知识,现将自己的理解整理成此。
关于生成器(generator)
为了节省空间,一边循环以便计算出后续元素的机制称为生成器:generator
创建一个generator的方法:
- 把一个列表生成式的[]改成()。
S = [x+x for x in range(7)] #普通的列表生成式
print(S)
G = (x+x for x in range(7)) #创建的生成器generator
for N in G: #循环将不断生成的元素输出,且不会出现使用next()的问题
print(N)
- 在定义创建函数时添加yield语句,变成generator的函数,在每次next()的时候执行,遇到yield语句返回值,再次执行时从上次返回的yield语句处执行。
def fib(max): #创建fib生成器
n,a,b = 0,0,1 #变量
while n<max: #当n的值小于max的值时有以下操作
yield b #Generator的标识性语句,此函数中获得的值为b
a,b = b,a+b #给a赋b的值,给b赋a+b的值
n = n+1
return 'done' #return语句的返回值为done
g = fib(7) #新建g为generator的对象
while True: #当while后面的条件为真时
try: #定义try代码块
x=next(g) #返回生成的每一个值到x
print("fib:",x) #输出生成的值
except StopIteration as s: #若提示StopIteration的错误则执行以下代码块,并用s代替StopIteration
print("Generator return value:",s.value) #输出生成器的返回值
break #代码块结束
'''
后面的while可以用for循环代替,但是使用for循环就无法获取Generator的返回值
for g in fib(7):
print next(g)
'''
使用方法:
在调用一个generators时,首先得生成一个generator对象,然后在next()函数不断获得下一个返回值
注意:
- 虽然是通过next()函数来获取下一个返回值,但是用for循环直接进行迭迭代更方便快速,更不会出现StopIteration的错误;
- for循环获取值的缺点是无法获取generator的return语句返回值,就必须捕获StopIteration错误,返回值包含在StopIteration的value中,这里使用except捕获错误值。
关于协程(coroutine)
- 普通的子程序的执行:多个子程序A调用B,B调用C,执行过程就是C执行完毕返回—>B执行完毕返回—>A执行完毕,一个线程就是执行一个子程序,在子程序的执行过程中有点像多线程,为线程切换;
- 协程为单线程执行,在执行一个程序的时候,不需要中断子程序,不是线程切换,而是子程序切换;
- 协程不需要锁机制,不存在多线程的同时写变量冲突,只需要判断状态。
关于generator与coroutine
- 由于协程是一个线程执行,那么最简单利用多核CPU的办法就是多进程+协程,既充分利用多核,有充分发挥协程的高效率,可获得极高的性能。Python对协程的支持是通过generator实现的,在generator中,我们不但可以通过for循环来迭代,还可以不断调用next()函数获取yield语句返回的下一个值。但是Python的yield但可以返回一个值,它还可以接受调用者发出的参数。
下面是一个简单的协程举例:
def gxnu(): #创建一个名为consumer的generator
r = '' #变量r
while True: #若while后面的条件为真
i = yield r #该生成器通过yeild获取m的值并将返回值赋给i,然后又将结果返回给produce继续执行
if not i: #若i为none
return #返回
print('GXNU : %s' % i) #输出i
r = 'DONE' #赋给r返回字符串
def locs(g): #创建子程序locs
g.send(None) #启动generator
n = 0 #定义变量n并赋值
while n < 6: #while后面的条件为n小于6
n = n + 1 #将n+1的值循环赋给n
m = n + 2
print('LOCS : %s' % n) #输出n的值
r = g.send(m) #获取值后切换到gxnu执行即将m的值传送回gxnu
print('GXNU return value: %s' % r) #输出gxnu的return语句返回值
g.close() #当n>=5时,gxnu中while语句判断为假,yeild返回结果停止操作,关闭gxnu
g = gxnu() #构造g为gxnu的对象
locs(g) #将generator的对象作为子程序locs的参数运行
执行的过程中,yeild语句的作用是在函数中运行到yeild语句中的变量时,暂停函数的执行并将获取的值返回给generator,然后将结果返回给函数。
整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为协程,而非线程的抢占式多任务。