天天看點

python 異步程式設計

協程不是作業系統提供的,是一種使用者狀态内的上下文切換技術,簡言而之,其實就是通過一個線程實作代碼塊互相切換執行。

上述代碼是普通的函數定義和執行,按流程分别執行兩個函數中的代碼,并先後會輸出:<code>1、2、3、4</code>。但如果介入協程技術那麼就可以實作函數見代碼切換執行,最終輸入:<code>1、3、2、4</code> 。

python種有多種可以實作協程的方式,例如:

greenlet,是一個第三方實作協程的代碼,(Gevent協程就是通過greenlet實作的)

yield,生成器,借助生成器的特點亦可以實作協程代碼

asyncio,在python3.4 種引入的子產品,用于編寫協程代碼

async &amp; awiat,在python3.5種引入的兩個關鍵字,結合asyncio子產品可以友善白那些協程代碼

greentlet是一個第三方子產品,需要提前安裝 <code>pip3 install greenlet</code>才能使用。

在python3.4 之後官方提供的正式支援協程

async &amp; awit 關鍵字在Python3.5版本中正式引入,基于他編寫的協程代碼其實就是 上一示例 的加強版,讓代碼可以更加簡便。

Python3.8之後 <code>@asyncio.coroutine</code> 裝飾器就會被移除,推薦使用async &amp; awit 關鍵字實作協程代碼。

協程就是可以通過一個線程在多個上下文種進行來回切換執行。但是協程協程來回切換執行的意義何在呢?

計算型的操作,利用協程來回切換執行,沒有任何意義,來回切換并儲存狀态 反倒會降低性能。

IO型的操作,利用協程在IO等待時間就去切換執行其他任務,當IO操作結束後再自動回調,那麼就會大大節省資源并提供性能,進而實作異步程式設計(不等待任務結束就可以去執行其他代碼)

基于<code>async</code> &amp; <code>await</code>關鍵字的協程可以實作異步程式設計,這也是目前python異步相關的主流技術。

想要真正的了解Python中内置的異步程式設計,根據下文的順序一點點來看。

事件循環,可以把他當做是一個while循環,這個while循環在周期性的運作并執行一些<code>任務</code>,在特定條件下終止循環。

在編寫程式時候可以通過如下代碼來擷取和建立事件循環。

協程函數,定義形式為 <code>async def</code> 的函數。

協程對象,調用 協程函數 所傳回的對象。

注意:調用協程函數時,函數内部代碼不會執行,隻是會傳回一個協程對象。

程式中,如果想要執行協程函數的内部代碼,需要 <code>事件循環</code> 和 <code>協程對象</code> 配合才能實作,如:

這個過程可以簡單了解為:将<code>協程</code>當做任務添加到 <code>事件循環</code> 的任務清單,然後事件循環檢測清單中的<code>協程</code>是否 已準備就緒(預設可了解為就緒狀态),如果準備就緒則執行其内部代碼。

await是一個隻能在協程函數中使用的關鍵字,用于遇到IO操作時挂起 目前協程(任務),目前協程(任務)挂起過程中 事件循環可以去執行其他的協程(任務),目前協程IO處理完成時,可以再次切換回來執行await之後的代碼。代碼如下:

例二:

例三:

上述的所有示例都隻是建立了一個任務,即:事件循環的任務清單中隻有一個任務,是以在IO等待時無法示範切換到其他任務效果。

在程式想要建立多個任務對象,需要使用Task對象來實作。

官方:

Tasks are used to schedule coroutines concurrently.

When a coroutine is wrapped into a Task with functions like <code>asyncio.create_task()</code> the coroutine is automatically scheduled to run soon。

Tasks用于并發排程協程,通過<code>asyncio.create_task(協程對象)</code>的方式建立Task對象,這樣可以讓協程加入事件循環中等待被排程執行。除了使用 <code>asyncio.create_task()</code> 函數以外,還可以用低層級的 <code>loop.create_task()</code> 或 <code>ensure_future()</code> 函數。不建議手動執行個體化 Task 對象。

本質上是将協程對象封裝成task對象,并将協程立即加入事件循環,同時追蹤協程的狀态。

注意:<code>asyncio.create_task()</code> 函數在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低層級的 <code>asyncio.ensure_future()</code> 函數

例一:

注意:<code>asyncio.wait</code> 源碼内部會對清單中的每個協程執行ensure_future進而封裝為Task對象,是以在和wait配合使用時task_list的值為<code>[func(),func()]</code> 也是可以的。