Python 协程

Author: Borg March 8, 2019

Title: Python 协程 March 8, 2019

310 Chinese characters, 219 English words.



协程是比线程轻量,由 Python 自行处理控制流的切换,不像线程的切换需要借助操作系统,因此同样是IO密集型程序协程的效率比线程高。然而 Python 中 yield、yield from、async、await 的使用十分容易混淆,需要加以区分。 # 生成器 ## yield yield 用于定义生成器,这个基本都知道。生成器可以暂停运行返回数据,随后再恢复运行。外部也可以使用 .send() 方法给生成器内部发送数据。 ```Python def jumping_range(up_to): """Generator for the sequence of integers from 0 to up_to, exclusive. Sending a value into the generator will shift the sequence by that amount. """ index = 0 while index < up_to: jump = yield index if jump is None: jump = 1 index += jump if __name__ == '__main__': iterator = jumping_range(5) print(next(iterator)) # 0 print(iterator.send(2)) # 2 print(next(iterator)) # 3 print(iterator.send(-1)) # 2 for x in iterator: print(x) # 3, 4 ``` ## yield from yield from 后加迭代器(生成器也是迭代器),可以使生成器循环嵌套。 ```Python def bottom(): # Returning the yield lets the value that goes up the call stack to come right back # down. return (yield 42) def middle(): return (yield from bottom()) def top(): return (yield from middle()) # Get the generator. gen = top() value = next(gen) print(value) # Prints '42'. try: value = gen.send(value * 2) except StopIteration as exc: value = exc.value print(value) # Prints '84'. ``` # 协程 Python 3.4 时协程使用 asyncio 库实现,使用 asyncio.coroutine 装饰器把生成器标示为协程,该版本的协程使用 yield from。 ``` import asyncio # Borrowed from http://curio.readthedocs.org/en/latest/tutorial.html. @asyncio.coroutine def countdown(number, n): while n > 0: print('T-minus', n, '({})'.format(number)) yield from asyncio.sleep(1) n -= 1 loop = asyncio.get_event_loop() tasks = [ asyncio.ensure_future(countdown("A", 2)), asyncio.ensure_future(countdown("B", 3))] loop.run_until_complete(asyncio.wait(tasks)) loop.close() ``` ## async / await Python 3.5 引入 async / await 关键字来定义协程,async def 协程里不能使用 yield from 而应该使用 await 代替。yield from 与 await 区别在于 yield from 后加的是迭代器、asyncio 库返回的 Future , 而 await 后加的是协程或者可等待的对象(awaitable object),即定义了 __await__ 魔法方法的对象,该魔法方法返回迭代器。注意 await 后不能加生成器,因此必须区分清楚生成器还是协程。 ``` async def py35_coro(): await stuff() ``` 定义协程后依然需要借助 asynio 库来调度协程,详见 [python文档-Coroutines and Tasks][1] --- 注:以上代码摘自: [How the heck does async/await work in Python 3.5?](https://snarky.ca/how-the-heck-does-async-await-work-in-python-3-5/) [1]: https://docs.python.org/3/library/asyncio-task.html#running-tasks-concurrently

Comments:

You must log in to comment.