一文搞懂Python中的進程,線程和協(xié)程
1.什么是并發(fā)編程
并發(fā)編程是實現(xiàn)多任務協(xié)同處理,改善系統(tǒng)性能的方式。Python中實現(xiàn)并發(fā)編程主要依靠
進程(Process):進程是計算機中的程序關于某數據集合的一次運行實例,是操作系統(tǒng)進行資源分配的最小單位
線程(Thread):線程被包含在進程之中,是操作系統(tǒng)進行程序調度執(zhí)行的最小單位
協(xié)程(Coroutine):協(xié)程是用戶態(tài)執(zhí)行的輕量級編程模型,由單一線程內部發(fā)出控制信號進行調度
直接上一張圖看看三者概念間的關系。
這張圖說明了什么?首先,一條線程是進程中一個單一的順序控制流,一個進程可以并發(fā)多個線程執(zhí)行不同任務。協(xié)程由單一線程內部發(fā)出控制信號進行調度,而非受到操作系統(tǒng)管理,因此協(xié)程沒有切換開銷和同步鎖機制,具有極高的執(zhí)行效率。
進程、線程、協(xié)程間的特性決定了它們的應用場景不同:
協(xié)程常用于IO密集型工作,例如網絡資源請求等;而進程、線程常用于計算密集型工作,例如科學計算、人工神經網絡等。
接下來對每種并發(fā)編程方法進行詳細闡述。
2.進程與多進程
Python多進程依賴于標準庫mutiprocessing,進程類Process的常用方法如下
序號 | 方法 | 含義 |
---|---|---|
1 | start() | 創(chuàng)建一個Process子進程實例并執(zhí)行該實例的run()方法 |
2 | run() | 子進程需要執(zhí)行的目標任務 |
3 | join() | 主進程阻塞等待子進程直到子進程結束才繼續(xù)執(zhí)行,可以設置等待超時時間timeout |
4 | terminate() | 終止子進程 |
5 | is_alive() | 判斷子進程是否終止 |
6 | daemon | 設置子進程是否隨主進程退出而退出 |
創(chuàng)建多進程任務的實例如下
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(), "正在執(zhí)行...") time.sleep(0.2) if __name__ == "__main__": task = myProcess(name="testProcess") task.start() task.join() # 該語句會阻塞主進程直至子進程結束 print("----------------")
注意:Windows系統(tǒng)在子進程結束后會立即自動清除子進程實例;而Linux系統(tǒng)子進程實例僅當主進程結束后才被回收,在子進程結束但主進程仍在運行的時間內處于僵尸進程狀態(tài),會造成性能損失甚至死鎖。對子進程實例的手動回收可以通過
p.terminate() p.join()
完成,此外,start()函數也有清除僵尸進程的功能。在使用多進程處理任務時并非進程越多越好,因為進程切換會造成性能開銷。
3.線程與多線程
Python多線程依賴于標準庫threading,線程類Thread的常用方法如下表:
序號 | 方法 | 含義 |
---|---|---|
1 | start() | 創(chuàng)建一個Thread子線程實例并執(zhí)行該實例的run()方法 |
2 | run() | 子線程需要執(zhí)行的目標任務 |
3 | join() | 主進程阻塞等待子線程直到子線程結束才繼續(xù)執(zhí)行,可以設置等待超時時間timeout |
4 | is_alive() | 判斷子線程是否終止 |
5 | daemon | 設置子線程是否隨主進程退出而退出 |
關于線程與進程的關系,還有一個很生動的例子
把一條公路看作一道進程,那么公路上的各個車道就是進程中的各個線程。這些線程(車道)共享了進程(道路)的公共資源;這些線程(車道)之間可以并發(fā)執(zhí)行(各個車道相對獨立),也可以互相同步(交通信號燈)。
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!"
結果如下
在多線程并發(fā)過程中,若沒有控制好線程間的執(zhí)行邏輯,將可能產生死鎖現(xiàn)象,可以使用with關鍵詞在線程訪問臨界區(qū)結束后自動釋放鎖,也可使用release()方法手動釋放句柄。
4.協(xié)程與多協(xié)程
協(xié)程適用于I/O密集型而非計算密集型場景。在協(xié)程發(fā)起I/O請求后返回結果前往往有大量閑置時間——該時間可能用于網絡數據傳輸、獲取協(xié)議頭、服務器查詢數據庫等,而I/O請求本身并不耗時,因此協(xié)程可以發(fā)送一個請求后讓渡給系統(tǒng)干別的事,這就是協(xié)程提高性能的原因。
協(xié)程編程的框架如下:
- 創(chuàng)建協(xié)程對象并將其封裝成任務實例;
- 創(chuàng)建事件循環(huán)實例并監(jiān)聽任務隊列;
- 獲取協(xié)程結果(可在事件循環(huán)結束后獲取,或提前添加回調函數)。
一個嵌套協(xié)程的示例如下:
import asyncio, time # 內層協(xié)程 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()) # 外層協(xié)程main async def main(): # 創(chuàng)建三個協(xié)程對象并封裝成任務 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) # 外層協(xié)程func async def func(): for i in range(5): print("func:", i) # 外層任務列表 tasks = [asyncio.ensure_future(func()), asyncio.ensure_future(main())] # 創(chuàng)建事件循環(huán) loop = asyncio.get_event_loop() start = time.time() # 監(jiān)聽異步任務 loop.run_until_complete(asyncio.wait(tasks)) end = time.time() print("總耗時:", end - start)
5.總結
看了這么多概念可能有點暈了,下面這張表總結了本文的內容。總得來說,進程、線程、協(xié)程各有各的應用場景,不能說多進程、多線程、多協(xié)程就一定好,而是要根據具體的使用情況來確定。
到此這篇關于一文搞懂Python中的進程,線程和協(xié)程的文章就介紹到這了,更多相關Python進程 線程 協(xié)程內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python實現(xiàn)簡單的學生成績管理系統(tǒng)
這篇文章主要為大家詳細介紹了python實現(xiàn)簡單的學生成績管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02Python+Selenium隨機生成手機驗證碼并檢查頁面上是否彈出重復手機號碼提示框
這篇文章主要介紹了Python+Selenium隨機生成手機驗證碼并檢查頁面上是否彈出重復手機號碼提示框,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09Python腳本如何在bilibili中查找彈幕發(fā)送者
這篇文章主要介紹了如何在bilibili中查找彈幕發(fā)送者,本文給大家分享小編寫的一個python腳本來實現(xiàn)bilibili彈幕發(fā)送者,需要的朋友可以參考下2020-06-06Windows上安裝tensorflow 詳細教程(圖文詳解)
這篇文章主要介紹了Windows上安裝TENSORFLOW 詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-02-02anaconda3:conda not found報錯問題解決
這篇文章主要給大家介紹了關于anaconda3:conda not found報錯問題解決的相關資料,Anaconda指的是一個開源的Python發(fā)行版本,其包含了conda、Python等180多個科學包及其依賴項,需要的朋友可以參考下2023-10-10