網站首頁 編程語言 正文
1.什么是并發編程
并發編程是實現多任務協同處理,改善系統性能的方式。Python中實現并發編程主要依靠
進程(Process):進程是計算機中的程序關于某數據集合的一次運行實例,是操作系統進行資源分配的最小單位
線程(Thread):線程被包含在進程之中,是操作系統進行程序調度執行的最小單位
協程(Coroutine):協程是用戶態執行的輕量級編程模型,由單一線程內部發出控制信號進行調度
直接上一張圖看看三者概念間的關系。
這張圖說明了什么?首先,一條線程是進程中一個單一的順序控制流,一個進程可以并發多個線程執行不同任務。協程由單一線程內部發出控制信號進行調度,而非受到操作系統管理,因此協程沒有切換開銷和同步鎖機制,具有極高的執行效率。
進程、線程、協程間的特性決定了它們的應用場景不同:
協程常用于IO密集型工作,例如網絡資源請求等;而進程、線程常用于計算密集型工作,例如科學計算、人工神經網絡等。
接下來對每種并發編程方法進行詳細闡述。
2.進程與多進程
Python多進程依賴于標準庫mutiprocessing,進程類Process的常用方法如下
序號 | 方法 | 含義 |
---|---|---|
1 | start() | 創建一個Process子進程實例并執行該實例的run()方法 |
2 | run() | 子進程需要執行的目標任務 |
3 | join() | 主進程阻塞等待子進程直到子進程結束才繼續執行,可以設置等待超時時間timeout |
4 | terminate() | 終止子進程 |
5 | is_alive() | 判斷子進程是否終止 |
6 | daemon | 設置子進程是否隨主進程退出而退出 |
創建多進程任務的實例如下
import os, time
import multiprocessing
class myProcess(multiprocessing.Process):
def __init__(self, *args, **kwargs) -> None:
super().__init__()
self.name = kwargs['name']
def run(self):
print("process name:", self.name)
for i in range(10):
print(multiprocessing.current_process(), "process pid:",
os.getpid(), "正在執行...")
time.sleep(0.2)
if __name__ == "__main__":
task = myProcess(name="testProcess")
task.start()
task.join() # 該語句會阻塞主進程直至子進程結束
print("----------------")
注意:Windows系統在子進程結束后會立即自動清除子進程實例;而Linux系統子進程實例僅當主進程結束后才被回收,在子進程結束但主進程仍在運行的時間內處于僵尸進程狀態,會造成性能損失甚至死鎖。對子進程實例的手動回收可以通過
p.terminate()
p.join()
完成,此外,start()函數也有清除僵尸進程的功能。在使用多進程處理任務時并非進程越多越好,因為進程切換會造成性能開銷。
3.線程與多線程
Python多線程依賴于標準庫threading,線程類Thread的常用方法如下表:
序號 | 方法 | 含義 |
---|---|---|
1 | start() | 創建一個Thread子線程實例并執行該實例的run()方法 |
2 | run() | 子線程需要執行的目標任務 |
3 | join() | 主進程阻塞等待子線程直到子線程結束才繼續執行,可以設置等待超時時間timeout |
4 | is_alive() | 判斷子線程是否終止 |
5 | daemon | 設置子線程是否隨主進程退出而退出 |
關于線程與進程的關系,還有一個很生動的例子
把一條公路看作一道進程,那么公路上的各個車道就是進程中的各個線程。這些線程(車道)共享了進程(道路)的公共資源;這些線程(車道)之間可以并發執行(各個車道相對獨立),也可以互相同步(交通信號燈)。
rsrc = 10
lock = threading.Lock()
def task1(name):
global rsrc, lock
for i in range(5):
with lock:
rsrc += 1
print("task1:", rsrc)
return name + "has been done!"
def task2(name):
global rsrc, lock
for i in range(5):
lock.acquire()
rsrc -= 1
print("task2:", rsrc)
lock.release()
return name + "has been done!"
結果如下
在多線程并發過程中,若沒有控制好線程間的執行邏輯,將可能產生死鎖現象,可以使用with關鍵詞在線程訪問臨界區結束后自動釋放鎖,也可使用release()方法手動釋放句柄。
4.協程與多協程
協程適用于I/O密集型而非計算密集型場景。在協程發起I/O請求后返回結果前往往有大量閑置時間——該時間可能用于網絡數據傳輸、獲取協議頭、服務器查詢數據庫等,而I/O請求本身并不耗時,因此協程可以發送一個請求后讓渡給系統干別的事,這就是協程提高性能的原因。
協程編程的框架如下:
- 創建協程對象并將其封裝成任務實例;
- 創建事件循環實例并監聽任務隊列;
- 獲取協程結果(可在事件循環結束后獲取,或提前添加回調函數)。
一個嵌套協程的示例如下:
import asyncio, time
# 內層協程
async def do_some_work(x):
print('Waiting: ', x)
await asyncio.sleep(x)
return 'Done after {}s'.format(x)
def OnCallBack(res):
print(res.result())
# 外層協程main
async def main():
# 創建三個協程對象并封裝成任務
task1 = asyncio.ensure_future(do_some_work(1))
task2 = asyncio.ensure_future(do_some_work(8))
task3 = asyncio.ensure_future(do_some_work(4))
# 添加回調
task1.add_done_callback(OnCallBack)
task2.add_done_callback(OnCallBack)
task3.add_done_callback(OnCallBack)
# 內層任務列表
tasks = [task1, task2, task3]
# 將列表轉為可等待對象
dones, pendings = await asyncio.wait(tasks)
# 外層協程func
async def func():
for i in range(5):
print("func:", i)
# 外層任務列表
tasks = [asyncio.ensure_future(func()), asyncio.ensure_future(main())]
# 創建事件循環
loop = asyncio.get_event_loop()
start = time.time()
# 監聽異步任務
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print("總耗時:", end - start)
5.總結
看了這么多概念可能有點暈了,下面這張表總結了本文的內容。總得來說,進程、線程、協程各有各的應用場景,不能說多進程、多線程、多協程就一定好,而是要根據具體的使用情況來確定。
原文鏈接:https://blog.csdn.net/FRIGIDWINTER/article/details/124369567
相關推薦
- 2022-07-13 Docker 數據管理
- 2024-03-09 【Redis】Redis中的布隆過濾器
- 2022-08-02 使用shell讀取ini文件方法步驟_linux shell
- 2023-02-05 前端面試學習中幾個常見有用的知識點_經驗交流
- 2022-08-15 前端寫代碼的時候,不滿足條件程序停止執行下面的程序,并彈窗提示
- 2022-08-20 在?pytorch?中實現計算圖和自動求導_python
- 2023-05-06 Python數據容器dict(字典)的實現_python
- 2022-05-02 Python實現PDF文字識別提取并寫入CSV文件_python
- 最近更新
-
- 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同步修改后的遠程分支