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