
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
发表评论
最新留言
第一次来,支持一个
[***.219.124.196]2025年04月06日 16时59分41秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Java 回调机制
2021-05-14
7、回归和特征选择
2021-05-14
pycharm使用(新建工程、字体修改、调试)
2021-05-14
什么是Numpy、Numpy教程
2021-05-14
Python学习笔记——元组
2021-05-14
异常声音检测
2021-05-14
PCB学习笔记——AD17如何添加新的封装
2021-05-14
numpy版本问题
2021-05-14
无法打开文件“opencv_world330d.lib”的解决办法
2021-05-14
maven项目通过Eclipse上传到svn上面,再导入到本地出现指定的类找不到的问题
2021-05-14
maven 项目部署到tomcat下 没有class文件
2021-05-14
算法训练 未名湖边的烦恼(递归,递推)
2021-05-14
算法训练 完数(循环,数学知识)
2021-05-14
什么是接口
2021-05-14
2020版nodejs12.18.3安装配置教程
2021-05-14
iview组件库中,Form组件里的Input,无法正确绑定on-enter事件
2021-05-14
记录-基于springboot+vue.js实现的超大文件分片极速上传及流式下载
2021-05-14