python中的协程
发布日期:2021-05-08 09:44:33 浏览次数:19 分类:精选文章

本文共 3089 字,大约阅读时间需要 10 分钟。

协程Coroutine,看上去也是子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。

1. 生成器generator

列表可以通过类似下面的方式实现:

L = [x * x for x in range(1, 11) if x % 2 == 0]
把一个列表生成式的[]改成(),就创建了一个generator:
G = (x * x for x in range(1, 11) if x % 2 == 0)
然后用迭代器去取出generator的元素:

for g in G:    print(g)

有的时候生成器是由函数推导过来的,比如:

def fib(max):    n, a, b = 0, 0, 1    while n < max:        print(b)        a, b = b, a + b        n = n + 1    return 'done'

将其中的print改为yield,这个函数就变成了一个generator:

def fib(max):    n, a, b = 0, 0, 1    while n < max:        yield b        a, b = b, a + b        n = n + 1    return 'done'

generator和普通函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

注意用生成器是没有办法获得return值的,需要捕获StopIteration错误,返回值包含在StopIteration的value中:

F = fib(6)while True:    try:        print(next(F))    except StopIteration as e:        print('Generator return value:', e.value)        break

注意要break。

generator还有一个send方法,有一个参数,该参数指定的是上一次被挂起的yield语句的返回值。总的来说,send方法和next方法唯一的区别是在执行send方法会首先把上一次挂起的yield语句的返回值通过参数设定,从而实现与生成器方法的交互。但是需要注意,在一个生成器对象没有执行next方法之前,由于没有yield语句被挂起,所以执行send方法会报错。

总结来说,receive=yield value包含了3个步骤:

1、向函数外抛出(返回)value
2、暂停(pause),等待next()或send()恢复
3、赋值receive=MockGetValue() 。 这个MockGetValue()是假想函数,用来接收send()发送进来的值。
下面是一个综合的例子:

def consumer():    r = ''    while True:        n = yield r        print('[CONSUMER] Consuming %s...' % n)        r = '200 OK'def produce(c):    next(c)    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)

2 yield from和asyncio

yield from iterable本质上等于for item in iterable: yield item的缩写版,如下例:

def f_wrapper(fun_iterable):    print('start')    yield from fun_iterable    print('end')def fib(max):    n, a, b = 0, 0, 1    while n < max:        yield b        a, b = b, a + b        n = n + 1    return 'done'wrap = f_wrapper(fib(5))for i in wrap:    print(i,end=' ')

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。

通过@asyncio.coroutine可以声明函数为协程,然后我们通过事件循环来调度协程,如下例:

import asyncio,random@asyncio.coroutinedef smart_fib(n):    index = 0    a = 0    b = 1    while index < n:        sleep_secs = random.uniform(0, 0.2)        yield from asyncio.sleep(sleep_secs) #通常yield from后都是接的耗时操作        print('Smart one think {} secs to get {}'.format(sleep_secs, b))        a, b = b, a + b        index += 1@asyncio.coroutinedef stupid_fib(n):    index = 0    a = 0    b = 1    while index < n:        sleep_secs = random.uniform(0, 0.4)        yield from asyncio.sleep(sleep_secs) #通常yield from后都是接的耗时操作        print('Stupid one think {} secs to get {}'.format(sleep_secs, b))        a, b = b, a + b        index += 1if __name__ == '__main__':    loop = asyncio.get_event_loop()    tasks = [        smart_fib(10),        stupid_fib(10),    ]    loop.run_until_complete(asyncio.wait(tasks))    print('All fib finished.')    loop.close()

简化写法是:把@asyncio.coroutine改为函数前的asynic,然后把yield from改为awiat

上一篇:树结构笔记
下一篇:运筹系列28:网络单纯形法

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2025年04月06日 16时59分41秒