Python 非同步程式設計原理篇之新舊協程實現對比
再來回顧一下協程的發展流程:
python2.5 為生成器引用.send()、.throw()、.close()方法
python3.3 為引入yield from,可以接收返回值,可以使用yield from定義協程
Python3.4 加入了asyncio模組
Python3.5 增加async、await關鍵字,在語法層面的提供支援
python3.7 使用 async def + await 的方式定義協程
python3.10 移除 以 yield from 的方式定義協程
舊協程
是指以
yield
、
yield from
等生成器語法為基礎的協程實現
新協程
是指以
asyncio
、
async
、
await
等關鍵字為基礎的協程實現
兩種協程的實現方式在協程發展史上有一段交集,並且舊協程基於生成器的協程語法讓生成器和協程兩個概念混淆,所以對學習者會造成一定的困擾。本篇主要說明兩種協程的實現方式的差異。
|
舊協程以yield關鍵字為核心,透過yield關鍵提供的程式碼執行暫停、恢復的能力,實現函式交替的執行,cpu的轉讓等能力。
import timedef consume(): r = '' while True: n = yield r print(f'[consumer] 開始消費 {n}...') time.sleep(1) r = f'{n} 消費完成'def produce(c): next(c) n = 0 while n < 5: n = n + 1 print(f'[producer] 生產了 {n}...') r = c.send(n) print(f'[producer] consumer return: {r}') c.close()if __name__=='__main__': c = consume() produce(c)
執行結果:
[producer] 生產了 1...[consumer] 開始消費 1...[producer] consumer return: 1 消費完成[producer] 生產了 2...[consumer] 開始消費 2...[producer] consumer return: 2 消費完成[producer] 生產了 3...[consumer] 開始消費 3...[producer] consumer return: 3 消費完成[producer] 生產了 4...[consumer] 開始消費 4...[producer] consumer return: 4 消費完成[producer] 生產了 5...[consumer] 開始消費 5...[producer] consumer return: 5 消費完成
結果分析:
當消費者
consume
執行到
n = yield r
時,流程暫停,將cpu交還給呼叫方
produce
。
在
asyncio初識篇中提到過,協程最重要的兩個因素是
事件迴圈
+
任務
。用yield實現的協程中,
consume
和
produce
中的 while迴圈共同作用下實現了一個事件迴圈的功能,
yield
和
send
實現了任務的暫停和繼續執行。
總結來說協程需要的兩個能力
事件迴圈
和
任務暫停和繼續
,在舊協程中的實現分別是:
- 事件迴圈透過手動編寫while迴圈程式碼實現
- 程式碼暫停繼續執行透過yield生成器的能力實現
|
新協程是
asyncio
、
async
、
await
等關鍵字實現的。新協程是基於事件迴圈機制實現的,核心能力包括事件迴圈,任務,回撥機制等。三者提供的能力分別是
- asyncio 提供了事件迴圈
- async 提供了協程標識
- await 提供了流程掛起能力
import asyncioasync 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")# 建立事件迴圈loop = asyncio.get_event_loop()# 建立任務task1 = loop.create_task(coro1())task2 = loop.create_task(coro2())# 執行協程loop.run_until_complete(asyncio.gather(task1, task2))# 關閉事件迴圈loop.close()
結果
start coro1start coro2end coro2end coro1
結果分析:
當
coro1
執行到
await asyncio.sleep(2)
時,流程掛起,將cpu交還給事件迴圈,等待事件迴圈的下一次排程,而事件迴圈排程到
coro2
繼續執行。
協程的兩個重要能力
事件迴圈
和
任務暫停和繼續
,分別的實現者:
- 事件迴圈透過asyncio提供的loop實現
- 程式掛起透過 await 關鍵字實現
|
asyncio
和
yield
是用於實現非同步程式設計的兩種不同的機制。
yield
是一種用於生成器(Generator)函式的關鍵字,用於建立可暫停和恢復執行的函式。當一個函式中包含
yield
語句時,它會返回一個生成器物件,可以透過呼叫生成器的
next()
方法或使用
for
迴圈來逐步迭代生成器函式中的值。
透過使用
yield
,我們可以將一個函式分割成多個程式碼塊,並在每個程式碼塊之間進行切換執行。這使得我們可以在函式執行過程中臨時掛起函式的執行,然後再次恢復執行。
asyncio
是 Python 提供的標準庫,用於編寫非同步程式碼。它基於事件迴圈(Event Loop)模式,允許我們在單執行緒中處理多個併發任務,並透過協程(Coroutine)來管理非同步操作。
asyncio
使用了
async
和
await
這兩個關鍵字來定義協程函式。在協程函式中可以使用
await
關鍵字來暫停當前協程的執行,等待某個非同步操作的完成,然後恢復執行。
總結來說:
舊協程:透過
yield關鍵字的暫停和恢復執行的能力實現協程
新協程:透過
事件迴圈機制,await關鍵字掛起流程能力實現協程
|
await
關鍵字和
yield
關鍵字都可以用於控制流的暫停和恢復,都屬於python的關鍵字,但是它們在協程的實現上有所不同。
相同點:
-
控制流暫停和恢復:無論是
await
還是yield
,它們都可以使程式碼在某個點暫停執行,並在稍後的時間點繼續執行。 -
協程支援:
await
和yield
都與協程(Coroutine)密切相關。它們都能夠用於定義和管理協程,使得非同步程式碼的編寫更加簡單和易讀。
區別:
-
語法差異:
await
是 Python 3.5 引入的關鍵字,用於非同步函式中暫停執行等待非同步操作完成。而yield
是早期協程的關鍵字,主要用於生成器(Generator)函式,用於建立迭代器和實現惰性計算,早期透過生成器的能力來實現協程。 - 語義:
-
await
表示當前協程需要等待一個非同步操作的完成,並掛起執行,讓其他任務有機會執行。 -
yield
是將執行的控制權交給呼叫方,同時儲存函式的狀態,以便在下次迭代時從上一次暫停的位置恢復執行。await將程式掛起,讓事件迴圈排程新的任務。yield將程式掛起,等待呼叫方的下一步指令。
-
上下文:
await
必須在非同步上下文中使用,例如在非同步函式中或者在async with
塊中。而yield
可以在普通函式中使用,即使沒有使用協程的上下文。 -
返回值:
yield
返回生成器物件,透過呼叫next()
方法或使用for
迴圈逐步迭代生成器中的值。而await
返回一個可等待物件(Awaitable),它可以是Future
、Task
、Coroutine
等。
總結:
await 不是透過 yield 來實現的程式暫停和執行,兩者有相似的能力,但完全沒有呼叫關係,都是屬於python關鍵字。
-
await
適用於非同步程式設計場景,用於等待非同步操作的完成,同時支援更靈活的協程管理。 -
yield
則主要用於生成器函式,用於實現迭代器和惰性計算。
它們在應用場景和語法上存在一些差異,但都為我們提供了控制流的暫停和恢復的能力。
以上就是新舊協程的實現方法,對比了兩種協程的實現方法,比較了yield關鍵字既作為生成器又實現協程有點混淆的用法,比較了都可以暫停恢復的關鍵字yield和await。這些內容是協程原理的核心知識,理解有難度。
來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70036594/viewspace-3004130/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- python——asyncio模組實現協程、非同步程式設計(三)Python非同步程式設計
- Python非同步IO程式設計之-asyncio協程應用例子Python非同步程式設計
- Python_非同步程式設計-併發程式設計-協程和futurePython非同步程式設計
- Python協程與JavaScript協程的對比PythonJavaScript
- python之非同步程式設計Python非同步程式設計
- 對執行緒、協程和同步非同步、阻塞非阻塞的理解執行緒非同步
- python網路-多工實現之協程Python
- Java非同步程式設計:CompletableFuture與Future的對比Java非同步程式設計
- python中非同步非阻塞如何實現Python非同步
- python之IO併發-阻塞IO 非阻塞IO IO多路複用 非同步IO(協程)Python非同步
- python非同步程式設計之asyncio初識Python非同步程式設計
- 在Kotlin中如何利用協程進行非同步程式設計Kotlin非同步程式設計
- JAVA程式設計習慣之equals對比Java程式設計
- Python教程:sort和sorted實現排序之對比Python排序
- Java協程程式設計之Loom專案嚐鮮Java程式設計OOM
- 玩轉 PHP 網路程式設計之原理篇PHP程式設計
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- 非同步程式設計方案----Promise實現小解非同步程式設計Promise
- Generator(生成器),入門初基,Coroutine(原生協程),登峰造極,Python3.10併發非同步程式設計async底層實現Python非同步程式設計
- Python非同步協程(asyncio詳解)Python非同步
- python大佬養成計劃–協程實現TCP連線PythonTCP
- 簡單理解非同步程式設計(python)和非同步程式設計(nodejs)非同步程式設計PythonNodeJS
- Linux中“新舊”TCP/IP工具的對比LinuxTCP
- Promise是如何實現非同步程式設計的?Promise非同步程式設計
- HttpCanary實現對HTTP2協議的抓包和注入(原理篇)HTTPPCA協議
- Python 非同步程式設計入門Python非同步程式設計
- python非同步IO程式設計(一)Python非同步程式設計
- 如何實現IIS 7.0對非HTTP協議的支援HTTP協議
- 【python】非同步IO | 協程 | asyncio | await | yieldPython非同步AI
- JS非同步程式設計之PromiseJS非同步程式設計Promise
- JS非同步程式設計之callbackJS非同步程式設計
- JS非同步程式設計之GeneratorJS非同步程式設計
- 新課程C++實用程式設計以上線!!!C++程式設計
- Python課程程式碼實現Python
- Go 併發程式設計 - runtime 協程排程(三)Go程式設計
- python教程:使用 async 和 await 協程進行併發程式設計PythonAI程式設計
- C++ concurrency::task實現非同步程式設計(WindowsC++非同步程式設計Windows
- 學習之路 / goroutine 併發協程池設計及實現Go