Python協程asyncio異步編程筆記分享
1.事件循環
可以理解成為一個死循環,去檢查任務列表中的任務,如果可執行就去執行,如果檢查不到就是不可執行的,那就忽略掉去執行其他可執行的任務,如果IO結束瞭(比如說去百度下載圖片,下載完瞭就會變成可執行任務)再去執行下載完成之後的邏輯
#這裡的任務是有狀態的,比如這個任務已經完成或者正在執行或者正在IO等待 任務列表 = [ 任務1, 任務2, 任務3,... ] while True: 可執行的任務列表,已完成的任務列表 = 去任務列表中檢查所有的任務,將'可執行'和'已完成'的任務返回 for 就緒任務 in 可執行的任務列表: 執行已就緒的任務 for 已完成的任務 in 已完成的任務列表: 在任務列表中移除 已完成的任務 如果 任務列表 中的任務都已完成,則終止循環
#在編寫程序時候可以通過如下代碼來獲取和創建事件循環。 import asyncio loop = asyncio.get_event_loop() #將任務放到任務列表,讓事件循環去檢測任務的狀態(是否可運行,是否IO) loop.loop.run_until_complete(任務)
2.協程和異步編程
協程函數,定義形式為 async def 的函數。
協程對象,調用 協程函數() 所返回的對象。
# 定義一個協程函數 async def func(): pass # 調用協程函數,返回一個協程對象(內部代碼不會執行) result = func()
2.1 基本使用
程序中,如果想要執行協程函數的內部代碼,需要 事件循環 和 協程對象 配合才能實現
示例1:
import asyncio async def func(): print("協程內部代碼") # 調用協程函數,返回一個協程對象。 result = func() # 方式一 # loop = asyncio.get_event_loop() # 創建一個事件循環 # loop.run_until_complete(result) # 將協程當做任務提交到事件循環的任務列表中,協程執行完成之後終止。 # 方式二 # 本質上方式一是一樣的,內部先 創建事件循環 然後執行 run_until_complete,一個簡便的寫法。 # asyncio.run 函數在 Python 3.7 中加入 asyncio 模塊, asyncio.run(result)
2.2 await
await+可等待對象(協程對象,Future,Task對象)
await是一個隻能在協程函數中使用的關鍵字,用於遇到IO操作時掛起 當前協程(任務),當前協程(任務)掛起過程中 事件循環可以去執行其他的協程(任務),當前協程IO處理完成時,可以再次切換回來執行await之後的代碼。
import asyncio async def func(): print("執行協程函數內部代碼") # 遇到IO操作掛起當前協程(任務),等IO操作完成之後再繼續往下執行。 # 當前協程掛起時,事件循環可以去執行其他協程(任務)。 #response是IO耗時結束後拿到的結果 response = await asyncio.sleep(2) print("IO請求結束,結果為:", response) result = func() asyncio.run(result)
結果
執行協程函數內部代碼
IO請求結束,結果為: None
#這裡返回None表示這個好事沒有啥意義,如果你是下載瞭一張圖片成功後會返回一個結果
示例2:
import asyncio async def others(): print("start") await asyncio.sleep(2) print('end') return '返回值' async def func(): print("執行協程函數內部代碼") # 遇到IO操作掛起當前協程(任務),等IO操作完成之後再繼續往下執行。當前協程掛起時,事件循環可以去執行其他協程(任務)。 response = await others() print("IO請求結束,結果為:", response) asyncio.run( func() )
執行結果:
執行協程函數內部代碼
start
end
IO請求結束,結果為: 返回值
示例3:
import asyncio async def others(): print("start") await asyncio.sleep(2) print('end') return '返回值' async def func(): print("執行協程函數內部代碼") # 遇到IO操作掛起當前協程(任務),等IO操作完成之後再繼續往下執行。當前協程掛起時,事件循環可以去執行其他協程(任務)。 #await等待有返回值才會向下執行 response1 = await others() print("IO請求結束,結果為:", response1) response2 = await others() print("IO請求結束,結果為:", response2) asyncio.run( func() )
執行結果:
執行協程函數內部代碼
start
end
IO請求結束,結果為: 返回值
start
end
IO請求結束,結果為: 返回值
下一步依賴上一步的結果時使用await,但如果有其他任務依然會切換到其他任務去執行
2.3 Task對象
在事件循環中添加多個任務。
Tasks用於並發調度協程,通過asyncio.create_task(協程對象)的方式創建Task對象,這樣可以讓協程加入事件循環中等待被調度執行。
除瞭使用 asyncio.create_task() 函數以外,還可以用低層級的 loop.create_task() 或 ensure_future() 函數。
不建議手動實例化 Task 對象。
本質上是將協程對象封裝成task對象,並將協程立即加入事件循環,同時追蹤協程的狀態。
註意:asyncio.create_task() 函數在 Python 3.7 中被加入。
在 Python 3.7 之前,可以改用低層級的 asyncio.ensure_future() 函數。
示例1:
import asyncio async def func(): print(1) await asyncio.sleep(2) print(2) return "返回值" async def main(): print("main開始") # 創建協程,將協程封裝到一個Task對象中並立即添加到事件循環的任務列表中,等待事件循環去執行(默認是就緒狀態)。 task1 = asyncio.create_task(func()) # 創建協程,將協程封裝到一個Task對象中並立即添加到事件循環的任務列表中,等待事件循環去執行(默認是就緒狀態)。 task2 = asyncio.create_task(func()) print("main結束") # 當執行某協程遇到IO操作時,會自動化切換執行其他任務。 # 此處的await是等待相對應的協程全都執行完畢並獲取結果 ret1 = await task1 ret2 = await task2 print(ret1, ret2) asyncio.run(main())
執行結果:
main開始
main結束
1
1
2
2
返回值 返回值
實例2:
import asyncio async def func(): print(1) await asyncio.sleep(2) print(2) return "返回值" async def main(): print("main開始") # 創建協程,將協程封裝到Task對象中並添加到事件循環的任務列表中,等待事件循環去執行(默認是就緒狀態)。 # 在調用 task_list = [ asyncio.create_task(func(), name="n1"), asyncio.create_task(func(), name="n2") ] print("main結束") # 當執行某協程遇到IO操作時,會自動化切換執行其他任務。 # 此處的await是等待所有協程執行完畢,並將所有協程的返回值保存到done # 如果設置瞭timeout值,則意味著此處最多等待的秒,完成的協程返回值寫入到done中,未完成則寫到pending中(比如下面的Timeout=1,要下載的圖片是兩秒,設為1秒就會執行失敗,done內為空,而pending中就是執行失敗的)。 done, pending = await asyncio.wait(task_list, timeout=None) print(done, pending) asyncio.run(main()) 執行結果: main開始 main結束 1 1 2 2 { <Task finished name='n1' coro=<func() done, defined at C:/Users/xuan.li/Desktop/unidevopss/py3x64/ibuildmaster/apps/PROD/tests.py:513> result='返回值'>, <Task finished name='n2' coro=<func() done, defined at C:/Users/xuan.li/Desktop/unidevopss/py3x64/ibuildmaster/apps/PROD/tests.py:513> result='返回值'> } set()
示例3:
import asyncio async def func(): print("執行協程函數內部代碼") # 遇到IO操作掛起當前協程(任務),等IO操作完成之後再繼續往下執行。當前協程掛起時,事件循環可以去執行其他協程(任務)。 response = await asyncio.sleep(2) print("IO請求結束,結果為:", response) coroutine_list = [func(), func()] # 錯誤:coroutine_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ] # 此處不能直接 asyncio.create_task,因為將Task立即加入到事件循環的任務列表, # 但此時事件循環還未創建,所以會報錯。 # 使用asyncio.wait將列表封裝為一個協程,並調用asyncio.run實現執行兩個協程 # asyncio.wait內部會對列表中的每個協程執行ensure_future,封裝為Task對象。 done,pending = asyncio.run( asyncio.wait(coroutine_list) )
以上就是Python協程asyncio 異步編程筆記分享的詳細內容,更多關於Python協程asyncio 異步編程的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- python協程與 asyncio 庫詳情
- python中Task封裝協程的知識點總結
- Python協程asyncio模塊的演變及高級用法
- python asyncio 協程庫的使用
- python進階之協程你瞭解嗎