1.背景:
項目中有用到協程,但是對于協程,線程,進程的區別還不是特別了解,所以用圖示的方式畫了出來,用于理清三者的概念。
2.概念理解:
2.1協程,線程,進程包含關系
- 一個系統可以有多個進程
- 一個進程可以有多個線程(多個線程為了提高進程的資源利用率)
- 一個線程可以有多個協程(多個協程為了提高線程的資源利用率)
2.2 共享資源范圍 ,隔離性, 通信方式,適用場景對比
PS:該表從Kimi拷貝
名稱 | 共享資源范圍? | 隔離性 | 通信方式 | 適用場景 |
進程 | 獨立內存空間、文件描述符、系統資源 | 高 | 管道、消息隊列、共享內存、套接字 | 適用于需要高隔離性和獨立資源的場景,如多用戶環境或需要保護數據安全的場景。 |
線程 | 進程內存空間、文件描述符、系統資源 | 低 | 共享內存、互斥鎖、條件變量 | 適用于需要共享內存和高效通信的場景,如多任務處理或計算密集型任務。 |
協程 | 線程內存空間、文件描述符、系統資源? | 非常低 | 異步機制(await 、asyncio.Queue ) | 適用于 I/O 密集型任務,如網絡請求、文件讀寫等,可以高效地利用單線程資源,避免線程切換的開銷。 |
3,協程執行過程示意圖
3.1 執行代碼
#異步調用
import asyncioasync def model_gen(task,time):# 模擬異步過程print('進入' + task)await asyncio.sleep(time) # 假設模型生成需要5秒print('處理繼續'+ task)await asyncio.sleep(time) # 假設模型生成需要5秒print('完成' + task)return task+'完成'async def main(name):# 異步調用print(name)#同步函數:asyncio.create_task() 是一個同步函數,它會立即返回一個 Task 對象。#返回的Task對象會被事件循環調度執行,asyncio.create_task() 本身不會等待任務完成。#asyncio.create_task() 提供了一種簡單的方式來將協程包裝成任務并提交到事件循環中,而不會阻塞調用它的線程。task1 = asyncio.create_task(model_gen('task1',4))print('create task1')task2 = asyncio.create_task(model_gen('task2',2))print('create task2')# 等待兩個任務完成,并獲取結果# await 是一個異步操作,當在協程中遇到 await 表達式時,當前協程會暫停執行,并將控制權交還給事件循環。result2 = await task2 # 協程掛載,task2執行完畢之后,才繼續執行后續作業print('hello')result1 = await task1 # task1執行完畢之后,才能繼續執行后續代碼# 打印結果print("所有任務完成!")print(result1)print(result2)#asyncio.run是同步函數,會阻塞當前線程,所以main('main1')全部執行完畢之后,才能執行main2的代碼
asyncio.run(main('main1'))
asyncio.run(main('main2'))
3.2 執行結果
main1
create task1
create task2
進入task1
進入task2
處理繼續task2
處理繼續task1
完成task2
hello
完成task1
所有任務完成!
task1完成
task2完成
main2
create task1
create task2
進入task1
進入task2
處理繼續task2
處理繼續task1
完成task2
hello
完成task1
所有任務完成!
task1完成
task2完成
3.3 執行圖解及理解
圖解如下:左邊三列是協程,第四列是線程的占用情況,最右邊是執行結果輸出。
個人理解:(如果有問題,歡迎指正,目前循環事件如何確定執行哪個協程的這一塊還沒有研究)
1)每個協程啟動之后,一直執行,直到掛起(比如await),可以是掛起多長時間,也可以是等待某個操作完成。掛起結束之后,協程變為可調用的狀態,供事件循環調用
2)事件循環從可調用的協程中,將其放到協程進行執行,直到該協程掛起,再取下一個可調用協程執行。
3)每次協程被調用之后,會一直執行直到下一次掛起(比如await),所以如果協程中有一個非常耗時的同步操作,就有可能導致包含該操作的協程一直占用線程,導致其他協程一直等待。所以寫異步程序時候,需要確認是否有非常耗時的同步操作。