1.事件循環(huán)
可以理解成為一個(gè)死循環(huán),去檢查任務(wù)列表中的任務(wù),如果可執(zhí)行就去執(zhí)行,如果檢查不到就是不可執(zhí)行的,那就忽略掉去執(zhí)行其他可執(zhí)行的任務(wù),如果IO結(jié)束了(比如說(shuō)去百度下載圖片,下載完了就會(huì)變成可執(zhí)行任務(wù))再去執(zhí)行下載完成之后的邏輯
1
2
3
4
5
6
7
8
9
|
#這里的任務(wù)是有狀態(tài)的,比如這個(gè)任務(wù)已經(jīng)完成或者正在執(zhí)行或者正在IO等待 任務(wù)列表 = [ 任務(wù) 1 , 任務(wù) 2 , 任務(wù) 3 ,... ] while True : 可執(zhí)行的任務(wù)列表,已完成的任務(wù)列表 = 去任務(wù)列表中檢查所有的任務(wù),將 '可執(zhí)行' 和 '已完成' 的任務(wù)返回 for 就緒任務(wù) in 可執(zhí)行的任務(wù)列表: 執(zhí)行已就緒的任務(wù) for 已完成的任務(wù) in 已完成的任務(wù)列表: 在任務(wù)列表中移除 已完成的任務(wù) 如果 任務(wù)列表 中的任務(wù)都已完成,則終止循環(huán) |
1
2
3
4
5
|
#在編寫(xiě)程序時(shí)候可以通過(guò)如下代碼來(lái)獲取和創(chuàng)建事件循環(huán)。 import asyncio loop = asyncio.get_event_loop() #將任務(wù)放到任務(wù)列表,讓事件循環(huán)去檢測(cè)任務(wù)的狀態(tài)(是否可運(yùn)行,是否IO) loop.loop.run_until_complete(任務(wù)) |
2.協(xié)程和異步編程
協(xié)程函數(shù),定義形式為 async def 的函數(shù)。
協(xié)程對(duì)象,調(diào)用 協(xié)程函數(shù)() 所返回的對(duì)象。
1
2
3
4
5
|
# 定義一個(gè)協(xié)程函數(shù) async def func(): pass # 調(diào)用協(xié)程函數(shù),返回一個(gè)協(xié)程對(duì)象(內(nèi)部代碼不會(huì)執(zhí)行) result = func() |
2.1 基本使用
程序中,如果想要執(zhí)行協(xié)程函數(shù)的內(nèi)部代碼,需要 事件循環(huán) 和 協(xié)程對(duì)象 配合才能實(shí)現(xiàn)
示例1:
1
2
3
4
5
6
7
8
9
10
11
12
|
import asyncio async def func(): print ( "協(xié)程內(nèi)部代碼" ) # 調(diào)用協(xié)程函數(shù),返回一個(gè)協(xié)程對(duì)象。 result = func() # 方式一 # loop = asyncio.get_event_loop() # 創(chuàng)建一個(gè)事件循環(huán) # loop.run_until_complete(result) # 將協(xié)程當(dāng)做任務(wù)提交到事件循環(huán)的任務(wù)列表中,協(xié)程執(zhí)行完成之后終止。 # 方式二 # 本質(zhì)上方式一是一樣的,內(nèi)部先 創(chuàng)建事件循環(huán) 然后執(zhí)行 run_until_complete,一個(gè)簡(jiǎn)便的寫(xiě)法。 # asyncio.run 函數(shù)在 Python 3.7 中加入 asyncio 模塊, asyncio.run(result) |
2.2 await
await+可等待對(duì)象(協(xié)程對(duì)象,F(xiàn)uture,Task對(duì)象)
await是一個(gè)只能在協(xié)程函數(shù)中使用的關(guān)鍵字,用于遇到IO操作時(shí)掛起 當(dāng)前協(xié)程(任務(wù)),當(dāng)前協(xié)程(任務(wù))掛起過(guò)程中 事件循環(huán)可以去執(zhí)行其他的協(xié)程(任務(wù)),當(dāng)前協(xié)程IO處理完成時(shí),可以再次切換回來(lái)執(zhí)行await之后的代碼。
1
2
3
4
5
6
7
8
9
10
|
import asyncio async def func(): print ( "執(zhí)行協(xié)程函數(shù)內(nèi)部代碼" ) # 遇到IO操作掛起當(dāng)前協(xié)程(任務(wù)),等IO操作完成之后再繼續(xù)往下執(zhí)行。 # 當(dāng)前協(xié)程掛起時(shí),事件循環(huán)可以去執(zhí)行其他協(xié)程(任務(wù))。 #response是IO耗時(shí)結(jié)束后拿到的結(jié)果 response = await asyncio.sleep( 2 ) print ( "IO請(qǐng)求結(jié)束,結(jié)果為:" , response) result = func() asyncio.run(result) |
結(jié)果
執(zhí)行協(xié)程函數(shù)內(nèi)部代碼
IO請(qǐng)求結(jié)束,結(jié)果為: None
#這里返回None表示這個(gè)好事沒(méi)有啥意義,如果你是下載了一張圖片成功后會(huì)返回一個(gè)結(jié)果
示例2:
1
2
3
4
5
6
7
8
9
10
11
12
|
import asyncio async def others(): print ( "start" ) await asyncio.sleep( 2 ) print ( 'end' ) return '返回值' async def func(): print ( "執(zhí)行協(xié)程函數(shù)內(nèi)部代碼" ) # 遇到IO操作掛起當(dāng)前協(xié)程(任務(wù)),等IO操作完成之后再繼續(xù)往下執(zhí)行。當(dāng)前協(xié)程掛起時(shí),事件循環(huán)可以去執(zhí)行其他協(xié)程(任務(wù))。 response = await others() print ( "IO請(qǐng)求結(jié)束,結(jié)果為:" , response) asyncio.run( func() ) |
執(zhí)行結(jié)果:
執(zhí)行協(xié)程函數(shù)內(nèi)部代碼
start
end
IO請(qǐng)求結(jié)束,結(jié)果為: 返回值
示例3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import asyncio async def others(): print ( "start" ) await asyncio.sleep( 2 ) print ( 'end' ) return '返回值' async def func(): print ( "執(zhí)行協(xié)程函數(shù)內(nèi)部代碼" ) # 遇到IO操作掛起當(dāng)前協(xié)程(任務(wù)),等IO操作完成之后再繼續(xù)往下執(zhí)行。當(dāng)前協(xié)程掛起時(shí),事件循環(huán)可以去執(zhí)行其他協(xié)程(任務(wù))。 #await等待有返回值才會(huì)向下執(zhí)行 response1 = await others() print ( "IO請(qǐng)求結(jié)束,結(jié)果為:" , response1) response2 = await others() print ( "IO請(qǐng)求結(jié)束,結(jié)果為:" , response2) asyncio.run( func() ) |
執(zhí)行結(jié)果:
執(zhí)行協(xié)程函數(shù)內(nèi)部代碼
start
end
IO請(qǐng)求結(jié)束,結(jié)果為: 返回值
start
end
IO請(qǐng)求結(jié)束,結(jié)果為: 返回值
下一步依賴上一步的結(jié)果時(shí)使用await,但如果有其他任務(wù)依然會(huì)切換到其他任務(wù)去執(zhí)行
2.3 Task對(duì)象
在事件循環(huán)中添加多個(gè)任務(wù)。
Tasks用于并發(fā)調(diào)度協(xié)程,通過(guò)asyncio.create_task(協(xié)程對(duì)象)的方式創(chuàng)建Task對(duì)象,這樣可以讓協(xié)程加入事件循環(huán)中等待被調(diào)度執(zhí)行。
除了使用 asyncio.create_task() 函數(shù)以外,還可以用低層級(jí)的 loop.create_task() 或 ensure_future() 函數(shù)。
不建議手動(dòng)實(shí)例化 Task 對(duì)象。
本質(zhì)上是將協(xié)程對(duì)象封裝成task對(duì)象,并將協(xié)程立即加入事件循環(huán),同時(shí)追蹤協(xié)程的狀態(tài)。
注意:asyncio.create_task() 函數(shù)在 Python 3.7 中被加入。
在 Python 3.7 之前,可以改用低層級(jí)的 asyncio.ensure_future() 函數(shù)。
示例1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import asyncio async def func(): print ( 1 ) await asyncio.sleep( 2 ) print ( 2 ) return "返回值" async def main(): print ( "main開(kāi)始" ) # 創(chuàng)建協(xié)程,將協(xié)程封裝到一個(gè)Task對(duì)象中并立即添加到事件循環(huán)的任務(wù)列表中,等待事件循環(huán)去執(zhí)行(默認(rèn)是就緒狀態(tài))。 task1 = asyncio.create_task(func()) # 創(chuàng)建協(xié)程,將協(xié)程封裝到一個(gè)Task對(duì)象中并立即添加到事件循環(huán)的任務(wù)列表中,等待事件循環(huán)去執(zhí)行(默認(rèn)是就緒狀態(tài))。 task2 = asyncio.create_task(func()) print ( "main結(jié)束" ) # 當(dāng)執(zhí)行某協(xié)程遇到IO操作時(shí),會(huì)自動(dòng)化切換執(zhí)行其他任務(wù)。 # 此處的await是等待相對(duì)應(yīng)的協(xié)程全都執(zhí)行完畢并獲取結(jié)果 ret1 = await task1 ret2 = await task2 print (ret1, ret2) asyncio.run(main()) |
執(zhí)行結(jié)果:
main開(kāi)始
main結(jié)束
1
1
2
2
返回值 返回值
實(shí)例2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import asyncio async def func(): print ( 1 ) await asyncio.sleep( 2 ) print ( 2 ) return "返回值" async def main(): print ( "main開(kāi)始" ) # 創(chuàng)建協(xié)程,將協(xié)程封裝到Task對(duì)象中并添加到事件循環(huán)的任務(wù)列表中,等待事件循環(huán)去執(zhí)行(默認(rèn)是就緒狀態(tài))。 # 在調(diào)用 task_list = [ asyncio.create_task(func(), name = "n1" ), asyncio.create_task(func(), name = "n2" ) ] print ( "main結(jié)束" ) # 當(dāng)執(zhí)行某協(xié)程遇到IO操作時(shí),會(huì)自動(dòng)化切換執(zhí)行其他任務(wù)。 # 此處的await是等待所有協(xié)程執(zhí)行完畢,并將所有協(xié)程的返回值保存到done # 如果設(shè)置了timeout值,則意味著此處最多等待的秒,完成的協(xié)程返回值寫(xiě)入到done中,未完成則寫(xiě)到pending中(比如下面的Timeout=1,要下載的圖片是兩秒,設(shè)為1秒就會(huì)執(zhí)行失敗,done內(nèi)為空,而pending中就是執(zhí)行失敗的)。 done, pending = await asyncio.wait(task_list, timeout = None ) print (done, pending) asyncio.run(main()) 執(zhí)行結(jié)果: main開(kāi)始 main結(jié)束 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:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import asyncio async def func(): print ( "執(zhí)行協(xié)程函數(shù)內(nèi)部代碼" ) # 遇到IO操作掛起當(dāng)前協(xié)程(任務(wù)),等IO操作完成之后再繼續(xù)往下執(zhí)行。當(dāng)前協(xié)程掛起時(shí),事件循環(huán)可以去執(zhí)行其他協(xié)程(任務(wù))。 response = await asyncio.sleep( 2 ) print ( "IO請(qǐng)求結(jié)束,結(jié)果為:" , response) coroutine_list = [func(), func()] # 錯(cuò)誤:coroutine_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ] # 此處不能直接 asyncio.create_task,因?yàn)閷ask立即加入到事件循環(huán)的任務(wù)列表, # 但此時(shí)事件循環(huán)還未創(chuàng)建,所以會(huì)報(bào)錯(cuò)。 # 使用asyncio.wait將列表封裝為一個(gè)協(xié)程,并調(diào)用asyncio.run實(shí)現(xiàn)執(zhí)行兩個(gè)協(xié)程 # asyncio.wait內(nèi)部會(huì)對(duì)列表中的每個(gè)協(xié)程執(zhí)行ensure_future,封裝為T(mén)ask對(duì)象。 done,pending = asyncio.run( asyncio.wait(coroutine_list) ) |
以上就是Python協(xié)程asyncio 異步編程筆記分享的詳細(xì)內(nèi)容,更多關(guān)于Python協(xié)程asyncio 異步編程的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!
原文鏈接:https://blog.csdn.net/weixin_47906106/article/details/120249639