python基礎教程:異步IO 之 API

Python的asyncio是使用 async/await 語法編寫併發代碼的標準庫。經過上一節的講解,咱們瞭解了它不斷變化的發展歷史。到了Python最新穩定版 3.7 這個版本,asyncio又作了比較大的調整,把這個庫的API分爲了 高層級API和低層級API,並引入asyncio.run()這樣的高級方法,讓編寫異步程序更加簡潔。shell

本節但願提綱挈領地介紹最新 3.7 版的asnycio,先從全局認識Python這個異步IO庫。編程

asyncio的高層級API主要提升以下幾個方面:安全

  • 併發地運行Python協程並徹底控制其執行過程;
  • 執行網絡IO和IPC;
  • 控制子進程;
  • 經過隊列實現分佈式任務;
  • 同步併發代碼。

asyncio的低層級API用以支持開發異步庫和框架:網絡

  • 建立和管理事件循環(event loop),提供異步的API用於網絡,運行子進程,處理操做系統信號等;
  • 經過transports實現高效率協議;
  • 經過async/await 語法橋架基於回調的庫和代碼。

asyncio高級API

高層級API讓咱們更方便的編寫基於asyncio的應用程序。這些API包括:架構

(1)協程和任務

協程經過 async/await 語法進行聲明,是編寫異步應用的推薦方式。歷史的 @asyncio.coroutine 和 yield from 已經被棄用,並計劃在Python 3.10中移除。協程能夠經過 asyncio.run(coro, *, debug=False) 函數運行,該函數負責管理事件循環並完結異步生成器。它應該被用做asyncio程序的主入口點,至關於main函數,應該只被調用一次。併發

任務被用於併發調度協程,可用於網絡爬蟲的併發。使用 asyncio.create_task() 就能夠把一個協程打包爲一個任務,該協程會自動安排爲很快運行。框架

協程,任務和Future都是可等待對象。其中,Future是低層級的可等待對象,表示一個異步操做的最終結果。異步

(2)流

流是用於網絡鏈接的高層級的使用 async/await的原語。流容許在不使用回調或低層級協議和傳輸的狀況下發送和接收數據。異步讀寫TCP有客戶端函數 asyncio.open_connection() 和 服務端函數 asyncio.start_server() 。它還支持 Unix Sockets: asyncio.open_unix_connection() 和 asyncio.start_unix_server()async

(3)同步原語

asyncio同步原語的設計相似於threading模塊的原語,有兩個重要的注意事項:
asyncio原語不是線程安全的,所以它們不該該用於OS線程同步(而是用threading)
這些同步原語的方法不接受超時參數; 使用asyncio.wait_for()函數執行超時操做。
asyncio具備如下基本同步原語:分佈式

  • Lock
  • Event
  • Condition
  • Semaphore
  • BoundedSemaphore

(4)子進程

asyncio提供了經過 async/await 建立和管理子進程的API。不一樣於Python標準庫的subprocess,asyncio的子進程函數都是異步的,而且提供了多種工具來處理這些函數,這就很容易並行執行和監視多個子進程。建立子進程的方法主要有兩個:

coroutine asyncio.create_subprocess_exec()
coroutine asyncio.create_subprocess_shell()

(5)隊列

asyncio 隊列的設計相似於標準模塊queue的類。雖然asyncio隊列不是線程安全的,但它們被設計爲專門用於 async/await 代碼。須要注意的是,asyncio隊列的方法沒有超時參數,使用 asyncio.wait_for()函數進行超時的隊列操做。
由於和標註模塊queue的類設計類似,使用起來跟queue無太多差別,只須要在對應的函數前面加 await 便可。asyncio 隊列提供了三種不一樣的隊列:

  • class asyncio.Queue 先進先出隊列
  • class asyncio.PriorityQueue 優先隊列
  • class asyncio.LifoQueue 後進先出隊列

(6)異常

asyncio提供了幾種異常,它們是:

  • TimeoutError,
  • CancelledError,
  • InvalidStateError,
  • SendfileNotAvailableError
  • IncompleteReadError
  • LimitOverrunError

asyncio低級API

低層級API爲編寫基於asyncio的庫和框架提供支持,有意編寫異步庫和框架的大牛們須要熟悉這些低層級API。主要包括:

(1)事件循環

事件循環是每一個asyncio應用程序的核心。 事件循環運行異步任務和回調,執行網絡IO操做以及運行子進程。

應用程序開發人員一般應該使用高級asyncio函數,例如asyncio.run(),而且不多須要引用循環對象或調用其方法。

Python 3.7 新增了 asyncio.get_running_loop()函數。

(2)Futures

Future對象用於將基於低層級回調的代碼與高層級的 async/await 代碼進行橋接。
Future表示異步操做的最終結果。 不是線程安全的。
Future是一個可等待對象。 協程能夠等待Future對象,直到它們有結果或異常集,或者直到它們被取消。
一般,Futures用於啓用基於低層級回調的代碼(例如,在使用asyncio傳輸實現的協議中)以與高層級 async/await 代碼進行互操做。

(3)傳輸和協議(Transports和Protocols)

Transport 和 Protocol由低層級事件循環使用,好比函數loop.create_connection()。它們使用基於回調的編程風格,並支持網絡或IPC協議(如HTTP)的高性能實現。

在最高級別,傳輸涉及字節的傳輸方式,而協議肯定要傳輸哪些字節(在某種程度上什麼時候傳輸)。

換種方式說就是:傳輸是套接字(或相似的I/O端點)的抽象,而協議是從傳輸的角度來看的應用程序的抽象。

另外一種觀點是傳輸和協議接口共同定義了一個使用網絡I/O和進程間I/O的抽象接口。

傳輸和協議對象之間始終存在1:1的關係:協議調用傳輸方法來發送數據,而傳輸調用協議方法來傳遞已接收的數據。

大多數面向鏈接的事件循環方法(例如loop.create_connection())一般接受protocol_factory參數,該參數用於爲接受的鏈接建立Protocol對象,由Transport對象表示。 這些方法一般返回(傳輸,協議)元組。

(4)策略(Policy)

事件循環策略是一個全局的按進程劃分的對象,用於控制事件循環的管理。 每一個事件循環都有一個默認策略,可使用策略API對其進行更改和自定義。

策略定義了上下文的概念,並根據上下文管理單獨的事件循環。 默認策略將上下文定義爲當前線程。

經過使用自定義事件循環策略,能夠自定義get_event_loop()set_event_loop()new_event_loop()函數的行爲。

(5)平臺支持

asyncio模塊設計爲可移植的,但因爲平臺的底層架構和功能,某些平臺存在細微的差別和限制。在Windows平臺,有些是不支持的,好比 loop.create_unix_connection() and loop.create_unix_server()。而Linux和比較新的macOS所有支持。

總結

Python 3.7 經過對asyncio分組使得它的架構更加清晰,普通寫異步IO的應用程序只需熟悉高層級API,須要寫異步IO的庫和框架時才須要理解低層級的API。

相關文章
相關標籤/搜索