Python異步編程之新舊協(xié)程的實(shí)現(xiàn)對(duì)比
1、協(xié)程的發(fā)展流程
再來(lái)回顧一下協(xié)程的發(fā)展流程:
- python2.5 為生成器引用.send()、.throw()、.close()方法
- python3.3 為引入yield from,可以接收返回值,可以使用yield from定義協(xié)程
- Python3.4 加入了asyncio模塊
- Python3.5 增加async、await關(guān)鍵字,在語(yǔ)法層面的提供支持
- python3.7 使用 async def + await 的方式定義協(xié)程
- python3.10 移除 以 yield from 的方式定義協(xié)程
舊協(xié)程
是指以yield
、yield from
等生成器語(yǔ)法為基礎(chǔ)的協(xié)程實(shí)現(xiàn)
新協(xié)程
是指以asyncio
、async
、await
等關(guān)鍵字為基礎(chǔ)的協(xié)程實(shí)現(xiàn)
兩種協(xié)程的實(shí)現(xiàn)方式在協(xié)程發(fā)展史上有一段交集,并且舊協(xié)程基于生成器的協(xié)程語(yǔ)法讓生成器和協(xié)程兩個(gè)概念混淆,所以對(duì)學(xué)習(xí)者會(huì)造成一定的困擾。本篇主要說(shuō)明兩種協(xié)程的實(shí)現(xiàn)方式的差異。
2、舊協(xié)程回顧
舊協(xié)程以yield關(guān)鍵字為核心,通過(guò)yield關(guān)鍵提供的代碼執(zhí)行暫停、恢復(fù)的能力,實(shí)現(xiàn)函數(shù)交替的執(zhí)行,cpu的轉(zhuǎn)讓等能力。
import time def consume(): r = '' while True: n = yield r print(f'[consumer] 開(kāi)始消費(fèi) {n}...') time.sleep(1) r = f'{n} 消費(fèi)完成' def produce(c): next(c) n = 0 while n < 5: n = n + 1 print(f'[producer] 生產(chǎn)了 {n}...') r = c.send(n) print(f'[producer] consumer return: {r}') c.close() if __name__=='__main__': c = consume() produce(c)
執(zhí)行結(jié)果:
[producer] 生產(chǎn)了 1...
[consumer] 開(kāi)始消費(fèi) 1...
[producer] consumer return: 1 消費(fèi)完成
[producer] 生產(chǎn)了 2...
[consumer] 開(kāi)始消費(fèi) 2...
[producer] consumer return: 2 消費(fèi)完成
[producer] 生產(chǎn)了 3...
[consumer] 開(kāi)始消費(fèi) 3...
[producer] consumer return: 3 消費(fèi)完成
[producer] 生產(chǎn)了 4...
[consumer] 開(kāi)始消費(fèi) 4...
[producer] consumer return: 4 消費(fèi)完成
[producer] 生產(chǎn)了 5...
[consumer] 開(kāi)始消費(fèi) 5...
[producer] consumer return: 5 消費(fèi)完成
結(jié)果分析:
當(dāng)消費(fèi)者consume
執(zhí)行到n = yield r
時(shí),流程暫停,將cpu交還給調(diào)用方produce
。
在asyncio初識(shí)篇中提到過(guò),協(xié)程最重要的兩個(gè)因素是事件循環(huán)
+ 任務(wù)
。用yield實(shí)現(xiàn)的協(xié)程中,consume
和 produce
中的 while循環(huán)共同作用下實(shí)現(xiàn)了一個(gè)事件循環(huán)的功能,yield
和 send
實(shí)現(xiàn)了任務(wù)的暫停和繼續(xù)執(zhí)行。
總結(jié)來(lái)說(shuō)協(xié)程需要的兩個(gè)能力事件循環(huán)
和任務(wù)暫停和繼續(xù)
,在舊協(xié)程中的實(shí)現(xiàn)分別是:
- 事件循環(huán)通過(guò)手動(dòng)編寫(xiě)while循環(huán)代碼實(shí)現(xiàn)
- 代碼暫停繼續(xù)執(zhí)行通過(guò)yield生成器的能力實(shí)現(xiàn)
3、新協(xié)程回顧
新協(xié)程是asyncio
、async
、await
等關(guān)鍵字實(shí)現(xiàn)的。新協(xié)程是基于事件循環(huán)機(jī)制實(shí)現(xiàn)的,核心能力包括事件循環(huán),任務(wù),回調(diào)機(jī)制等。三者提供的能力分別是
- asyncio 提供了事件循環(huán)
- async 提供了協(xié)程標(biāo)識(shí)
- await 提供了流程掛起能力
import asyncio async def coro1(): print("start coro1") await asyncio.sleep(2) print("end coro1") async def coro2(): print("start coro2") await asyncio.sleep(1) print("end coro2") # 創(chuàng)建事件循環(huán) loop = asyncio.get_event_loop() # 創(chuàng)建任務(wù) task1 = loop.create_task(coro1()) task2 = loop.create_task(coro2()) # 運(yùn)行協(xié)程 loop.run_until_complete(asyncio.gather(task1, task2)) # 關(guān)閉事件循環(huán) loop.close()
結(jié)果
start coro1
start coro2
end coro2
end coro1
結(jié)果分析:
當(dāng)coro1
執(zhí)行到 await asyncio.sleep(2)
時(shí),流程掛起,將cpu交還給事件循環(huán),等待事件循環(huán)的下一次調(diào)度,而事件循環(huán)調(diào)度到coro2
繼續(xù)執(zhí)行。
協(xié)程的兩個(gè)重要能力事件循環(huán)
和 任務(wù)暫停和繼續(xù)
,分別的實(shí)現(xiàn)者:
- 事件循環(huán)通過(guò)asyncio提供的loop實(shí)現(xiàn)
- 程序掛起通過(guò) await 關(guān)鍵字實(shí)現(xiàn)
4、新舊協(xié)程實(shí)現(xiàn)的對(duì)比
asyncio
和 yield
是用于實(shí)現(xiàn)異步編程的兩種不同的機(jī)制。
yield
是一種用于生成器(Generator)函數(shù)的關(guān)鍵字,用于創(chuàng)建可暫停和恢復(fù)執(zhí)行的函數(shù)。當(dāng)一個(gè)函數(shù)中包含 yield
語(yǔ)句時(shí),它會(huì)返回一個(gè)生成器對(duì)象,可以通過(guò)調(diào)用生成器的 next()
方法或使用 for
循環(huán)來(lái)逐步迭代生成器函數(shù)中的值。
通過(guò)使用 yield
,我們可以將一個(gè)函數(shù)分割成多個(gè)代碼塊,并在每個(gè)代碼塊之間進(jìn)行切換執(zhí)行。這使得我們可以在函數(shù)執(zhí)行過(guò)程中臨時(shí)掛起函數(shù)的執(zhí)行,然后再次恢復(fù)執(zhí)行。
asyncio
是 Python 提供的標(biāo)準(zhǔn)庫(kù),用于編寫(xiě)異步代碼。它基于事件循環(huán)(Event Loop)模式,允許我們?cè)趩尉€程中處理多個(gè)并發(fā)任務(wù),并通過(guò)協(xié)程(Coroutine)來(lái)管理異步操作。
asyncio
使用了 async
和 await
這兩個(gè)關(guān)鍵字來(lái)定義協(xié)程函數(shù)。在協(xié)程函數(shù)中可以使用 await
關(guān)鍵字來(lái)暫停當(dāng)前協(xié)程的執(zhí)行,等待某個(gè)異步操作的完成,然后恢復(fù)執(zhí)行。
總結(jié)來(lái)說(shuō):
舊協(xié)程:通過(guò)yield關(guān)鍵字的暫停和恢復(fù)執(zhí)行的能力實(shí)現(xiàn)協(xié)程
新協(xié)程:通過(guò)事件循環(huán)機(jī)制,await關(guān)鍵字掛起流程能力實(shí)現(xiàn)協(xié)程
5、await 和 yield 的關(guān)系
await
關(guān)鍵字和 yield
關(guān)鍵字都可以用于控制流的暫停和恢復(fù),都屬于python的關(guān)鍵字,但是它們?cè)趨f(xié)程的實(shí)現(xiàn)上有所不同。
相同點(diǎn):
- 控制流暫停和恢復(fù):無(wú)論是
await
還是yield
,它們都可以使代碼在某個(gè)點(diǎn)暫停執(zhí)行,并在稍后的時(shí)間點(diǎn)繼續(xù)執(zhí)行。 - 協(xié)程支持:
await
和yield
都與協(xié)程(Coroutine)密切相關(guān)。它們都能夠用于定義和管理協(xié)程,使得異步代碼的編寫(xiě)更加簡(jiǎn)單和易讀。
區(qū)別:
1.語(yǔ)法差異:await
是 Python 3.5 引入的關(guān)鍵字,用于異步函數(shù)中暫停執(zhí)行等待異步操作完成。而 yield
是早期協(xié)程的關(guān)鍵字,主要用于生成器(Generator)函數(shù),用于創(chuàng)建迭代器和實(shí)現(xiàn)惰性計(jì)算,早期通過(guò)生成器的能力來(lái)實(shí)現(xiàn)協(xié)程。
2.語(yǔ)義:
await
表示當(dāng)前協(xié)程需要等待一個(gè)異步操作的完成,并掛起執(zhí)行,讓其他任務(wù)有機(jī)會(huì)執(zhí)行。
yield
是將執(zhí)行的控制權(quán)交給調(diào)用方,同時(shí)保存函數(shù)的狀態(tài),以便在下次迭代時(shí)從上一次暫停的位置恢復(fù)執(zhí)行。
await將程序掛起,讓事件循環(huán)調(diào)度新的任務(wù)。yield將程序掛起,等待調(diào)用方的下一步指令。
3.上下文:await
必須在異步上下文中使用,例如在異步函數(shù)中或者在 async with
塊中。而 yield
可以在普通函數(shù)中使用,即使沒(méi)有使用協(xié)程的上下文。
4.返回值:yield
返回生成器對(duì)象,通過(guò)調(diào)用 next()
方法或使用 for
循環(huán)逐步迭代生成器中的值。而 await
返回一個(gè)可等待對(duì)象(Awaitable),它可以是 Future
、Task
、Coroutine
等。
總結(jié):
await 不是通過(guò) yield 來(lái)實(shí)現(xiàn)的程序暫停和執(zhí)行,兩者有相似的能力,但完全沒(méi)有調(diào)用關(guān)系,都是屬于python關(guān)鍵字。
await
適用于異步編程場(chǎng)景,用于等待異步操作的完成,同時(shí)支持更靈活的協(xié)程管理。yield
則主要用于生成器函數(shù),用于實(shí)現(xiàn)迭代器和惰性計(jì)算。
它們?cè)趹?yīng)用場(chǎng)景和語(yǔ)法上存在一些差異,但都為我們提供了控制流的暫停和恢復(fù)的能力。
以上就是Python異步編程之新舊協(xié)程的實(shí)現(xiàn)對(duì)比的詳細(xì)內(nèi)容,更多關(guān)于Python協(xié)程的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
QT5 Designer 打不開(kāi)的問(wèn)題及解決方法
這篇文章主要介紹了QT5 Designer 打不開(kāi)的問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Django中實(shí)現(xiàn)一個(gè)高性能計(jì)數(shù)器(Counter)實(shí)例
這篇文章主要介紹了Django中實(shí)現(xiàn)一個(gè)高性能計(jì)數(shù)器(Counter)實(shí)例,分解成一步一步去講解,并配有例子,需要的朋友可以參考下2014-07-07Python抓新型冠狀病毒肺炎疫情數(shù)據(jù)并繪制全國(guó)疫情分布的代碼實(shí)例
在本篇文章里小編給大家整理了一篇關(guān)于Python抓新型冠狀病毒肺炎疫情數(shù)據(jù)并繪制全國(guó)疫情分布的代碼實(shí)例,有興趣的朋友們可以學(xué)習(xí)下。2020-02-02Python常用爬蟲(chóng)代碼總結(jié)方便查詢
今天小編就為大家分享一篇關(guān)于Python常用爬蟲(chóng)代碼總結(jié)方便查詢,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02Pandas之使用drop_duplicates:去除重復(fù)項(xiàng)
這篇文章主要介紹了Pandas之使用drop_duplicates:去除重復(fù)項(xiàng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Python基于分析Ajax請(qǐng)求實(shí)現(xiàn)抓取今日頭條街拍圖集功能示例
這篇文章主要介紹了Python基于分析Ajax請(qǐng)求實(shí)現(xiàn)抓取今日頭條街拍圖集功能,涉及Python針對(duì)今日頭條URL請(qǐng)求與json數(shù)據(jù)處理相關(guān)操作技巧,需要的朋友可以參考下2018-07-07