[Python] 关于generator与coroutine

近几天学习了关于生成器与协程的相关知识,现将自己的理解整理成此。

关于生成器(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()函数不断获得下一个返回值
注意:

  1. 虽然是通过next()函数来获取下一个返回值,但是用for循环直接进行迭迭代更方便快速,更不会出现StopIteration的错误;
  2. 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协作完成任务,所以称为协程,而非线程的抢占式多任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值