Asyncio在Python中提供的API很複雜,其旨在替不一樣羣體的人解決不一樣的問題,也正是因爲這個緣由,因此很難區分重點。python
能夠根據asyncio在Python中的特性,將其劃分爲兩大主要羣體:
1. 應用(最終用戶)開發者,想要在應用開發中使用asyncio;
2. 框架開發者,製做框架或庫以供應用開發者在他們的開發中使用。編程
在asyncio社區中大部分的問題基本都與這兩個部分相關,例如,asyncio的官方文檔更像是給框架開發者使用的,而非應用開發者,這致使應用開發者在閱讀文檔時很容易被其複雜性所震撼,給讀者一種錯覺就是在使用它以前,得看徹底部的文檔。bash
不須要關心官方文檔的內容,要掌握asyncio庫比想象中要容易。網絡
PEP 492的做者、async Python的主要貢獻者——Yury Selivanov——曾說過,asyncio的不少API都是給框架開發者提供的,應用開發人員須要掌握的只是全部API中的一小部分。框架
在本節咱們將研究這些核心特性,並瞭解如何在Python中使用基於事件loop的編程,以此實現基本的異步。異步
要成爲一個掌握asyncio的應用開發者,你須要知道的東西其實能夠用一個小例子來展現。socket
import time import asyncio async def main(): print(f'{time.ctime()} Hello') await asyncio.sleep(1.0) print(f'{time.ctime()} Goodbye') loop.stop() # 1 loop = asyncio.get_event_loop() # 2 loop.create_task(main()) # 3 loop.run_forever() # 4 pending = asyncio.Task.all_tasks(loop=loop) group = asyncio.gather(*pending, return_exceptions=True) # 5 loop.run_until_complete(group) # 6 loop.close() # 7
λ python quickstart.py Fri Sep 28 19:39:33 2018 Hello Fri Sep 28 19:39:34 2018 Goodbye
loop.run_forever()
方法,在收到中止信號時中止循環,而後收集那些還未完成的task,調用loop.run_until_complete()
方法等待其執行完畢,但更多的是用這個方法收集協程任務並取消它們,而後等待其執行完畢;loop.stop()
方法的基礎上使用,會致使循環永久消失。上述例子漏了一些東西,其中最重要的是如何運行阻塞函數,咱們知道協程就是函數中使用了await
關鍵字進行切換,但在當前async def
還沒得到普遍支持前,使用阻塞函數/庫是不可避免的。async
爲此,asyncio提供了一個與concurrent.futures
包中的API相似的API,它提供了ThreadPoolExecutor
和ProcessPoolExecutor
,默認基於線程,但很容易用基於進程的替換,這裏面有些特殊的地方要注意。函數
import time import asyncio async def main(): print(f'{time.ctime()} Hello') await asyncio.sleep(1.0) print(f'{time.ctime()} Goodbye') loop.stop() def blocking(): # 1 time.sleep(0.5) # 2 print(f'{time.ctime()} Hello from a thread!') loop = asyncio.get_event_loop() loop.create_task(main()) loop.run_in_executor(None, blocking) # 3 loop.run_forever() pending = asyncio.Task.all_tasks(loop=loop) # 4 group = asyncio.gather(*pending) loop.run_until_complete(group) loop.close()
λ python quickstart_exe.py Fri Sep 28 20:21:21 2018 Hello Fri Sep 28 20:21:22 2018 Hello from a thread! Fri Sep 28 20:21:22 2018 Goodbye
好了,經過上面的學習,已經掌握了應用開發者對於asyncio庫須要的最重要的部分,接下來將拓展知識並對API進行層次理解,這會讓你更容易理解如何從文檔中獲取信息。工具
從前面一節發現,應用開發者只需幾個命令就可使用asyncio,但不幸的是官方文檔巨量的API和扁平化的顯示格式,讓人很難分清哪些命令更通用,哪些命令是向框架開發者提供的,框架開發者能夠經過文檔尋找鉤子並鏈接到其框架中,接下來咱們從框架開發者的角度來看他們如何構建新的異步兼容庫。
Level | Concept | Implementation |
---|---|---|
9 | Network: streams | StreamReader & StreamWriter |
8 | Network: TCP & UDP | Protocol |
7 | Network: transports | BaseTransport |
6 | tools | asyncio.Queue |
5 | subprocesses & threads | run_in_executor(), asyncio.subprocess |
4 | tasks | asyncio.Task |
3 | futures | asyncio.Future |
2 | event loop | BaseEventLoop |
1 | coroutines | async def & await |
上表中加粗字體對於應用開發者最重要,級別分爲9級,1級最基礎。
Curio
和Trio
中並不經常使用,它們只依賴於Python中的本地協程,不依賴asyncio庫模塊;uvloop
實現了比標準庫更快的循環;asyncio.Queue
,提供與Queue
模塊相似的API,但原版的get和put方法會阻塞線程,所以這裏提供的隊列經過增長wait
關鍵字以支持異步;在QuickStart中,掌握了快速上手的幾個API;如今,對整個asyncio有了清晰的層級劃分。這裏再對上述知識進行強調:
若是使用提供異步兼容的第三方庫,如aiohttp
,那麼就不用直接使用asyncio的網絡層,但這會致使對第三方庫的依賴。
隨着Python的發展,asyncio庫之後可能會提供更多的API,如今也只是大體地分了幾個層級。