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