網站首頁 編程語言 正文
引言
普遍意義上講,生成器是一種特殊的迭代器,它可以在執行過程中暫停并在恢復執行時保留它的狀態。而協程,則可以讓一個函數在執行過程中暫停并在恢復執行時保留它的狀態,在Python3.10中,原生協程的實現手段,就是生成器,或者說的更具體一些:協程就是一種特殊的生成器,而生成器,就是協程的入門心法。
協程底層實現
我們知道,Python3.10中可以使用async和await關鍵字來實現原生協程函數的定義和調度,但其實,我們也可以利用生成器達到協程的效果,生成器函數和普通函數的區別在于,生成器函數使用 yield 語句來暫停執行并返回結果。例如,下面是一個使用生成器函數實現的簡單協程:
def my_coroutine():
while True:
x = yield
print(x)
# 使用生成器函數創建協程
coroutine = my_coroutine()
# 啟動協程
next(coroutine)
# 在協程中傳入數據
coroutine.send(1)
coroutine.send(2)
coroutine.send(3)
程序返回:
? ?mydemo git:(master) ? /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/mydemo/src/test.py" ?
1 ?
2 ?
3
在上面的代碼中,生成器函數 my_coroutine 使用了一個無限循環來實現協程的邏輯。每當調用 send 方法時,協程就會從 yield 語句處恢復執行,并將傳入的參數賦值給變量 x。
如此,就完成了協程執行-》阻塞-》切換-》回調的工作流模式。
當然,作為事件循環機制,協程服務啟動可能無限期地運行,要關閉協程服務,可以使用生成器的close()方法。當一個協程被關閉時,它會生成GeneratorExit異常,該異常可以用生成器的方式進行捕獲:
def my_coroutine():
try :
while True:
x = yield
print(x)
except GeneratorExit:
print("協程關閉")
# 使用生成器函數創建協程
coroutine = my_coroutine()
# 啟動協程
next(coroutine)
# 在協程中傳入數據
coroutine.send(1)
coroutine.send(2)
coroutine.send(3)
coroutine.close()
程序返回:
? ?mydemo git:(master) ? /opt/homebrew/bin/python3.10 "/Users/liuyue/wodfan/work/mydemo/src/test.py" ?
1 ?
2 ?
3 ?
協程關閉
業務場景
在實際業務場景中,我們也可以使用生成器來模擬協程流程,主要體現在數據的IO流操作中,假設我們需要從本地往服務器傳輸數據,首先建立鏈接對象:
class Connection:
def __init__(self, addr):
self.addr = addr
def transmit(self, data):
print(f"X: {data[0]}, Y: {data[1]} sent to {self.addr}")
隨后建立生成器函數:
def send_to_server(conn):
while True:
try:
raw_data = yield
raw_data = raw_data.split(' ')
coords = (float(raw_data[0]), float(raw_data[1]))
conn.transmit(coords)
except ConnectionError:
print("鏈接丟失,進行回調")
conn = Connection("重新連接v3u.cn")
利用生成器調用鏈接類的transmit方法進行數據的模擬傳輸,如果鏈接斷開,則會觸發回調重新連接,執行邏輯:
if __name__ == '__main__':
conn = Connection("v3u.cn")
sender = send_to_server(conn)
sender.send(None)
for i in range(1, 6):
sender.send(f"{100/i} {200/i}")
# 模擬鏈接斷開
conn.addr = None
sender.throw(ConnectionError)
for i in range(1, 6):
sender.send(f"{100/i} {200/i}")
程序返回:
X: 100.0, Y: 200.0 sent to v3u.cn
X: 50.0, Y: 100.0 sent to v3u.cn
X: 33.333333333333336, Y: 66.66666666666667 sent to v3u.cn
X: 25.0, Y: 50.0 sent to v3u.cn
X: 20.0, Y: 40.0 sent to v3u.cn
鏈接丟失,進行回調
X: 100.0, Y: 200.0 sent to 重新連接v3u.cn
X: 50.0, Y: 100.0 sent to 重新連接v3u.cn
X: 33.333333333333336, Y: 66.66666666666667 sent to 重新連接v3u.cn
X: 25.0, Y: 50.0 sent to 重新連接v3u.cn
X: 20.0, Y: 40.0 sent to 重新連接v3u.cn
如此,我們就可以利用生成器的“狀態保留”機制來控制網絡鏈接突然斷開的回調補救措施了。
所以說,協程就是一種特殊的生成器:
async def test():
pass
print(type(test()))
您猜怎么著?
<class 'coroutine'>
結語
誠然,生成器和協程也并非完全是一個概念,與生成器不同的是,協程可以被另一個函數(稱為調用方)恢復執行,而不是只能由生成器本身恢復執行。這使得協程可以用來實現更復雜的控制流,因為它們可以在執行時暫停并在任意時刻恢復執行。
原文鏈接:https://juejin.cn/post/7181766056719941690
相關推薦
- 2022-03-20 C語言輸出任意邊長的菱形(用c語言輸出一個菱形)
- 2023-01-20 Go語言實現定時器的原理及使用詳解_Golang
- 2023-04-07 C#快速實現IList非泛型類接口的自定義類作為數據源_C#教程
- 2024-03-14 SpringBoot中RestTemplate 發送http請求
- 2022-06-07 C++11中跳轉initializer_list實現分析_C 語言
- 2022-11-26 Ubuntu?環境下安裝?Docker環境詳解_docker
- 2022-02-02 Maven命令安裝本地jar包到本地倉庫
- 2022-12-23 Android用注解與反射實現Butterknife功能_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支