asyncio在3.4版本添加到Python中,但经过
async def
和await
关键字建立coroutines的语法是3.5才加入的,在这以前,人们把generators看成coroutines来使用,在一些老的语法中,你能够看到用@asyncio.coroutine
之类的装饰器加yield
的句式,在本文中,请摒弃过去的写法。bash
async def
关键字>>> async def f(): # 1 ... return 123 >>> type(f) # 2 <class 'function'> >>> import inspect # 3 >>> inspect.iscoroutinefunction(f) True
正是因为在3.4版本用生成器看成协程来使用,因此在3.5版本中,async def
的用法以及效果与生成器几乎相同。咱们经过代码来观察Python如何在不一样协程中切换,首先先看下如何得到return的值。async
当coroutine return的时候,将会抛出一个StopIteration
异常。函数
>>> async def f(): ... return 123 >>> coro = f() >>> try: ... coro.send(None) # 1 ... except StopIteration as e: ... print('The answer was: ', e.value) # 2 The answer was: 123
协程的开始和结束是经过send()和StopIteration来定义的,loop负责在背后作这些事,开发者只须要为loop安排task便可。oop
await
关键字await
关键字老是接收一个参数,其类型必须是awaitable的,必须是以下两种之一:
1. 一个coroutine;
2. 一个实现了__await__()
方法的对象,这个方法必须返回一个迭代器。学习
async def f(): await asyncio.sleep(1.0) return 123 async def main(): result = await f() # 1 return result
在开始学习loop以前,了解一下如何向协程提供异常颇有用,异常一般用于取消协程,在task.cancel()
时,loop在内部使用coro.throw()
来抛出一个asyncio.CancelledError
。code
>>> coro = f() # 使用上面的协程 >>> coro.send(None) <Future pending> >>> coro.throw(Exception, 'hello') # 经过throw方法提供一个异常和值,该异常将在await处产生 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f Exception: hello
>>> async def f(): ... try: ... while True: await asyncio.sleep(0) ... except asyncio.CancelledError: ... print('I was cancelled!') ... else: ... return 111 >>> coro = f() >>> coro.send(None) >>> coro.send(None) >>> coro.throw(asyncio.CancelledError) I was cancelled! Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration # 正是因为内部捕捉了CancelledError,这个协程得以正常退出
>>> import asyncio >>> async def f(): ... try: ... while True: await asyncio.sleep(0) ... except asyncio.CancelledError: ... print('Cancelled') ... while True: await asyncio.sleep(0) # 跳转到另外一个协程上去了 ... else: return 1 >>> coro = f() >>> coro.send(None) >>> coro.throw(asyncio.CancelledError) Cancelled >>> coro.send(None)
目前为止的代码中,都是经过手动调用send(None)
和throw(asyncio.CancelledError)
来模拟loop的,下一章开始学习用loop来自动处理。协程
>>> async def f(): ... await asyncio.sleep(0) ... return 123 >>> loop = asyncio.get_event_loop() >>> loop.run_until_complete(f()) 123