-
Python中的異步編程
Python實現異步編程的方案有:
twisted
:使用事件驅動機制來提升python性能gevent
:使用greenlet在用戶態完成棧和上下文切換來減少切換帶來的性能損耗tornado
:使用生成器來保存協程上下文及狀態,使用原生的python語法實現了協程asyncio
:異步編程標準化。
-
Python異步編程的特點
- 單線程、異步阻塞
- 異步的實現基於協程,不僅使得Python中的異步是阻塞的,而且最小執行單位不再是單個任務,而是每個任務的一部分。
-
Python高併發方案的區別
多進程、多線程這類方案,IO的調度取決於系統;
協程,調度來自於用戶。
asyncio模塊實現異步,也是採用協程實現。
-
asyncio模塊的主要組件和概念
- 事件循環:asyncio模塊中,每一個進程都有一個事件循環。程序員把一些函數註冊到事件循環上,當滿足事件發生的時候,調用相應的協程函數;
- 協程:子程序的泛化概念,可以在執行期間暫停,等待外部的處理完成之後,從之前暫停的地方回覆執行。理解爲一個使用async關鍵字定義的函數。它的調用不會立即執行,而是會返回一個協程對象,協程對象需要註冊到事件循環,由事件循環調用;
- Futures:定義Future對象,表示尚未完成的計算;
- Tasks:用於封裝和管理並行模式下的協程;協程對象是一個可以掛起的函數,任務則是對協程進一步封裝,其中包含任務的各種狀態;
- async/await關鍵字:定義協程的關鍵字,async定義一個協程,await用於掛起阻塞的異步調用接口。
-
事件循環Event loop(維基百科)
事件的本質就是異步。
事件源:可以產生事件的實體;
事件處理者:能處理事件的實體;
事件循環:第三方實體。
事件循環的作用是管理所有的事件,在整個程序運行過程中不斷循環執行,追蹤事件發生的順序將它們放到隊列中,當主線程空閒的時候,調用相應的事件處理者處理事件。
-
協程與事件循環案例
import asyncio import time async def do_some_work(x): # async關鍵字定義一個協程 print('Waiting:', x) coroutine = do_some_work(2) # 協程的調用不會直接執行,而是返回一個協程對象 loop = asyncio.get_event_loop() # 創建一個事件循環 loop.run_until_complete(coroutine) # run_until_complete將協程註冊到事件循環,並啓動事件循環。
協程對象不能直接運行,在註冊事件循環時,
run_until_complete
將協程包裝成了一個task
。task
對象是Futurn
類的子類,保存了協程運行後的狀態,用於未來獲取協程的結果。import asyncio import time async def do_some_work(x): # async關鍵字定義一個協程 print('Waiting:', x) coroutine = do_some_work(2) # 協程的調用不會直接執行,而是返回一個協程對象 loop = asyncio.get_event_loop() # 創建一個事件循環 task = loop.create_task(coroutine) # 創建task,此時的task尚未加入事件循環,狀態爲pending loop.run_until_complete(task) # run_until_complete將task註冊到事件循環,並啓動事件循環。 # task執行完後,狀態爲finished
run_until_complete
參數是一個future對象
,當傳入的是:- 協程,會自動封裝成
task
task
,task
是Future
的子類。asyncio.ensure_future(coroutine)
和loop.create_task(coroutine)
都可以創建task
# 綁定回調函數 import asyncio import time async def do_some_work(x): # async關鍵字定義一個協程 print('Waiting:', x) return 'Done after {}s'.format(x) # 返回值 def callback(future): # 定義一個回調函數,最後一個參數是future對象,如果這裏有多個參數,下方通過偏函數導入 print('Callback: ', future.result()) # 返回future的結果 coroutine = do_some_work(2) # 協程的調用不會直接執行,而是返回一個協程對象 loop = asyncio.get_event_loop() # 創建一個事件循環 task = loop.create_task(coroutine) # 創建task,此時的task尚未加入事件循環,狀態爲pending task.add_done_callback(callback) # 綁定回調函數,在task執行完畢的時候獲取執行的結果 loop.run_until_complete(task) # run_until_complete將task註冊到事件循環,並啓動事件循環。 # task執行完後,狀態爲finished
coroutine執行結束時會調用回調函數,並通過參數future獲取協程執行的結果,此future是沒有傳入的,實際上與創建的task是同一個對象
# 阻塞和await import asyncio import time now = lambda: time.time() async def do_some_work(x): print('Waiting: ', x) await asyncio.sleep(x) # 執行sleep時,await使此協程主動讓出控制權,loop調用其他協程 return 'Done after {}s'.format(x) start = now() coroutine = do_some_work(2) loop = asyncio.get_event_loop() task = asyncio.ensure_future(coroutine) loop.run_until_complete(task) print('Task ret: ', task.result()) print('TIME: ', now() - start) # 以上還只有一個協程,讓出控制權也暫時無用,如果有多個協程,協程A讓出控制權,loop就會把控制權分配給協程B,實現了併發。 # asyncio實現併發:每當一個協程任務阻塞的時候就await,讓後其他協程繼續工作。 import asyncio import time now = lambda: time.time() async def do_some_work(x): print('Waiting: ', x) await asyncio.sleep(x) return 'Done after {}s'.format(x) start = now() coroutine1 = do_some_work(1) coroutine2 = do_some_work(2) coroutine3 = do_some_work(4) tasks = [ asyncio.ensure_future(coroutine1), asyncio.ensure_future(coroutine2), asyncio.ensure_future(coroutine3) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks)) # asyncio.wait(接收task列表);asyncio.gather(接收多個task) for task in tasks: print('Task ret: ', task.result()) print('TIME: ', now() - start)
- 協程,會自動封裝成
-
How the heck does async/await work in Python 3.5?
From Wikipedia, an eventloop is a programming construct that waits for and dispathches enents or messages in a program.Basically an event loop lets you go, “When A happens, do B”.
In Python’s case,
asyncio
was added to the standard library to provide an event loop. -
Reference
理解Python異步中的事件循環(asyncio管理事件循環)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.