Python并發(fā)執(zhí)行的幾種實(shí)現(xiàn)方法
1、Python中并發(fā)執(zhí)行實(shí)現(xiàn)方法
1.1 Python中并發(fā)執(zhí)行實(shí)現(xiàn)
在Python中,有幾種主要的并發(fā)執(zhí)行實(shí)現(xiàn)方法,包括多線程、多進(jìn)程和異步編程。
1.1.1 多線程(Threading)
Python標(biāo)準(zhǔn)庫(kù)中的threading模塊支持多線程編程。然而,由于Python的全局解釋器鎖(GIL),Python的多線程在CPU密集型任務(wù)上并不能實(shí)現(xiàn)真正的并行執(zhí)行。但在I/O密集型任務(wù)(如網(wǎng)絡(luò)請(qǐng)求、文件讀寫(xiě)等)上,多線程仍然可以顯著提升性能。
import threading def worker(): print("This is a thread running the worker function.") # 創(chuàng)建線程對(duì)象 threads = [] for _ in range(5): t = threading.Thread(target=worker) threads.append(t) t.start() # 等待所有線程完成 for t in threads: t.join()
1.1.2 多進(jìn)程(Multiprocessing)
Python的multiprocessing模塊支持多進(jìn)程編程,可以充分利用多核CPU的資源。每個(gè)進(jìn)程都有自己獨(dú)立的Python解釋器,因此不受GIL的限制。多進(jìn)程適用于CPU密集型任務(wù)。
import multiprocessing def worker(): print("This is a process running the worker function.") if __name__ == "__main__": processes = [] for _ in range(5): p = multiprocessing.Process(target=worker) processes.append(p) p.start() # 等待所有進(jìn)程完成 for p in processes: p.join()
1.1.3 異步編程(Asyncio)
Python 3.5引入了asyncio模塊,支持異步編程。異步編程可以在單線程內(nèi)實(shí)現(xiàn)非阻塞的I/O操作,提高程序的響應(yīng)速度和吞吐量。它特別適用于處理大量的并發(fā)I/O操作,如網(wǎng)絡(luò)請(qǐng)求。
import asyncio async def worker(): print("This is an async task running the worker function.") # 創(chuàng)建事件循環(huán) loop = asyncio.get_event_loop() tasks = [] for _ in range(5): task = loop.create_task(worker()) tasks.append(task) # 執(zhí)行所有任務(wù) loop.run_until_complete(asyncio.wait(tasks)) loop.close()
注意:異步編程與多線程和多進(jìn)程編程有所不同,它更多的是一種編程模型,而不是簡(jiǎn)單地創(chuàng)建多個(gè)執(zhí)行單元。異步編程需要理解并適應(yīng)其特有的編程模式和概念,如協(xié)程、事件循環(huán)等。
1.2 Python中多進(jìn)程和多線程的區(qū)別
在Python中,multiprocessing和threading模塊都用于實(shí)現(xiàn)并發(fā)執(zhí)行,但它們?cè)诘讓訖C(jī)制、使用場(chǎng)景和性能特點(diǎn)上有顯著的區(qū)別。
1.2.1 Multiprocessing多進(jìn)程
Multiprocessing模塊允許創(chuàng)建多個(gè)進(jìn)程來(lái)執(zhí)行Python代碼。每個(gè)進(jìn)程都有自己獨(dú)立的內(nèi)存空間和解釋器實(shí)例,因此它們之間不共享全局變量(除非通過(guò)特定的機(jī)制,如multiprocessing.Manager或multiprocessing.Value、multiprocessing.Array等)。這使得multiprocessing非常適合于計(jì)算密集型任務(wù),因?yàn)樗梢猿浞掷枚嗪薈PU并行處理任務(wù)。
由于每個(gè)進(jìn)程都有自己獨(dú)立的Python解釋器,進(jìn)程間通信(IPC)通常比線程間通信(通過(guò)共享內(nèi)存)要慢得多,并且需要顯式的IPC機(jī)制,如管道(Pipe)、隊(duì)列(Queue)、共享內(nèi)存(SharedMemory)等。
1.2.2 Threading多線程
Threading模塊允許創(chuàng)建多個(gè)線程來(lái)執(zhí)行Python代碼。線程共享同一個(gè)進(jìn)程的內(nèi)存空間,因此它們可以直接訪問(wèn)全局變量和大多數(shù)Python對(duì)象。這使得線程間通信相對(duì)簡(jiǎn)單,因?yàn)樗鼈兛梢灾苯幼x寫(xiě)共享的內(nèi)存。
然而,由于Python的全局解釋器鎖(GIL)的存在,同一時(shí)間內(nèi)只有一個(gè)線程可以執(zhí)行Python代碼。這意味著即使是多線程,CPU密集型任務(wù)的執(zhí)行速度也可能不會(huì)顯著提高。因此,threading模塊在Python中通常更適用于IO密集型任務(wù),如網(wǎng)絡(luò)請(qǐng)求、文件讀寫(xiě)等,這些任務(wù)通??梢栽谝粋€(gè)線程等待IO操作完成時(shí)讓另一個(gè)線程繼續(xù)執(zhí)行。
1.2.3 多進(jìn)程和多線程特性對(duì)比
- 資源共享:
- 多線程:在多線程中,所有線程共享同一個(gè)進(jìn)程的地址空間,這意味著它們可以訪問(wèn)相同的變量和內(nèi)存區(qū)域。因此,多線程間的數(shù)據(jù)共享和通信相對(duì)簡(jiǎn)單,但也容易引發(fā)數(shù)據(jù)同步和一致性的問(wèn)題,如競(jìng)態(tài)條件。
- 多進(jìn)程:每個(gè)進(jìn)程都有自己獨(dú)立的地址空間,這意味著它們無(wú)法直接共享數(shù)據(jù)。進(jìn)程間的通信需要通過(guò)特殊的機(jī)制來(lái)實(shí)現(xiàn),如管道、消息隊(duì)列、共享內(nèi)存或套接字等。雖然進(jìn)程間通信相對(duì)復(fù)雜,但它避免了多線程中的數(shù)據(jù)同步問(wèn)題。
- 全局解釋器鎖(GIL):
- 多線程:由于Python的全局解釋器鎖(GIL)的存在,Python的多線程在CPU密集型任務(wù)上并不能實(shí)現(xiàn)真正的并行執(zhí)行。GIL確保任何時(shí)候只有一個(gè)線程在執(zhí)行Python字節(jié)碼。因此,對(duì)于計(jì)算密集型任務(wù),多線程并不能帶來(lái)性能提升。
- 多進(jìn)程:多進(jìn)程不受GIL的限制,每個(gè)進(jìn)程都有自己獨(dú)立的Python解釋器,因此可以充分利用多核CPU的資源,實(shí)現(xiàn)真正的并行執(zhí)行。
- 性能開(kāi)銷(xiāo):
- 多線程:線程創(chuàng)建和銷(xiāo)毀的開(kāi)銷(xiāo)相對(duì)較小,因?yàn)榫€程共享進(jìn)程的內(nèi)存空間,無(wú)需復(fù)制數(shù)據(jù)。因此,對(duì)于需要頻繁創(chuàng)建和銷(xiāo)毀線程的應(yīng)用,多線程可能是一個(gè)更好的選擇。
- 多進(jìn)程:進(jìn)程創(chuàng)建和銷(xiāo)毀的開(kāi)銷(xiāo)相對(duì)較大,因?yàn)槊總€(gè)進(jìn)程都需要獨(dú)立的內(nèi)存空間和系統(tǒng)資源。此外,進(jìn)程間通信也需要額外的開(kāi)銷(xiāo)。因此,對(duì)于需要大量進(jìn)程的應(yīng)用,需要謹(jǐn)慎考慮性能問(wèn)題。
- 穩(wěn)定性:
- 多線程:由于線程共享數(shù)據(jù),如果一個(gè)線程崩潰,可能會(huì)導(dǎo)致整個(gè)進(jìn)程崩潰。
- 多進(jìn)程:每個(gè)進(jìn)程都是獨(dú)立的,一個(gè)進(jìn)程的崩潰不會(huì)影響其他進(jìn)程。因此,多進(jìn)程在穩(wěn)定性方面可能更有優(yōu)勢(shì)。
- 適用場(chǎng)景:
- 多線程:適用于I/O密集型任務(wù),如網(wǎng)絡(luò)請(qǐng)求、文件讀寫(xiě)等。在這些場(chǎng)景下,線程大部分時(shí)間都在等待I/O操作完成,因此可以充分利用多線程的優(yōu)勢(shì)。
- 多進(jìn)程:適用于CPU密集型任務(wù),如科學(xué)計(jì)算、圖像處理等。在這些場(chǎng)景下,多進(jìn)程可以充分利用多核CPU的資源,實(shí)現(xiàn)性能提升。
總之,選擇使用多線程還是多進(jìn)程取決于具體的任務(wù)類(lèi)型和性能需求。在Python中,對(duì)于I/O密集型任務(wù),可以使用多線程或異步編程;對(duì)于CPU密集型任務(wù),多進(jìn)程可能是一個(gè)更好的選擇。
1.3 等待信號(hào)量實(shí)現(xiàn)并發(fā)控制
信號(hào)量是一個(gè)計(jì)數(shù)器,用于控制同時(shí)訪問(wèn)某個(gè)特定資源或資源池的線程數(shù)量。信號(hào)量有一個(gè)值,表示可用的許可數(shù)。當(dāng)線程想要訪問(wèn)資源時(shí),它必須先獲取一個(gè)許可;如果許可數(shù)大于0,則獲取成功并減1;否則,線程將阻塞等待。
import threading sem = threading.Semaphore(3) # 允許三個(gè)線程同時(shí)訪問(wèn)資源 def worker(): sem.acquire() # 獲取許可 try: # 訪問(wèn)或修改共享資源 print("Thread is working with the shared resource.") finally: sem.release() # 釋放許可 # 創(chuàng)建并啟動(dòng)線程...
1.3.1 基于等待信號(hào)量實(shí)現(xiàn)多進(jìn)程并發(fā)
在Python中,基于等待信號(hào)量(Semaphore)實(shí)現(xiàn)多進(jìn)程并發(fā)通常涉及到multiprocessing模塊中的Semaphore類(lèi)。信號(hào)量用于控制對(duì)共享資源的訪問(wèn),允許一定數(shù)量的進(jìn)程同時(shí)訪問(wèn)該資源。當(dāng)信號(hào)量的值大于0時(shí),進(jìn)程可以獲得一個(gè)信號(hào)量許可來(lái)訪問(wèn)資源;當(dāng)信號(hào)量的值為0時(shí),進(jìn)程將阻塞,直到有其他進(jìn)程釋放一個(gè)許可。
下面是一個(gè)簡(jiǎn)單的例子,展示了如何使用multiprocessing.Semaphore來(lái)實(shí)現(xiàn)多進(jìn)程并發(fā)訪問(wèn)共享資源:
import multiprocessing import time import random # 設(shè)置信號(hào)量的初始值,這里允許3個(gè)進(jìn)程同時(shí)訪問(wèn)共享資源 semaphore = multiprocessing.Semaphore(3) def worker_process(process_id, semaphore): # 嘗試獲取信號(hào)量許可 semaphore.acquire() try: print(f"Process {process_id} acquired semaphore and is working.") # 模擬工作負(fù)載 time.sleep(random.random()) print(f"Process {process_id} finished working and releasing semaphore.") finally: # 無(wú)論是否發(fā)生異常,都要確保釋放信號(hào)量許可 semaphore.release() if __name__ == '__main__': # 創(chuàng)建進(jìn)程池 processes = [] for i in range(10): # 創(chuàng)建10個(gè)進(jìn)程 p = multiprocessing.Process(target=worker_process, args=(i, semaphore)) processes.append(p) p.start() # 等待所有進(jìn)程完成 for p in processes: p.join() print("All processes have finished.")
在這個(gè)例子中創(chuàng)建了10個(gè)進(jìn)程,但是通過(guò)信號(hào)量限制了同時(shí)訪問(wèn)共享資源的進(jìn)程數(shù)最多為3個(gè)。每個(gè)進(jìn)程在工作前都會(huì)嘗試獲取信號(hào)量的許可,如果信號(hào)量的值大于0,則獲取許可并開(kāi)始工作;如果信號(hào)量的值為0,則進(jìn)程會(huì)阻塞等待,直到有其他進(jìn)程釋放許可。每個(gè)進(jìn)程完成工作后會(huì)釋放其持有的信號(hào)量許可,這樣其他等待的進(jìn)程就可以獲取許可并開(kāi)始工作。
1.3.2 基于等待信號(hào)量實(shí)現(xiàn)多線程并發(fā)
在Python中,要實(shí)現(xiàn)基于等待信號(hào)量的多線程并發(fā),可以使用threading模塊中的Semaphore類(lèi)。信號(hào)量用于控制對(duì)共享資源的并發(fā)訪問(wèn)。當(dāng)信號(hào)量的值大于0時(shí),線程可以獲得一個(gè)信號(hào)量許可來(lái)訪問(wèn)資源;當(dāng)信號(hào)量的值為0時(shí),線程將阻塞,直到其他線程釋放一個(gè)許可。
下面是一個(gè)簡(jiǎn)單的例子,展示了如何使用threading.Semaphore來(lái)實(shí)現(xiàn)多線程并發(fā)訪問(wèn)共享資源:
import threading import time import random # 設(shè)置信號(hào)量的初始值,這里允許3個(gè)線程同時(shí)訪問(wèn)共享資源 semaphore = threading.Semaphore(3) def worker_thread(thread_id, semaphore): # 嘗試獲取信號(hào)量許可 semaphore.acquire() try: print(f"Thread {thread_id} acquired semaphore and is working.") # 模擬工作負(fù)載 time.sleep(random.random()) print(f"Thread {thread_id} finished working and releasing semaphore.") finally: # 無(wú)論是否發(fā)生異常,都要確保釋放信號(hào)量許可 semaphore.release() if __name__ == '__main__': # 創(chuàng)建線程列表 threads = [] for i in range(10): # 創(chuàng)建10個(gè)線程 t = threading.Thread(target=worker_thread, args=(i, semaphore)) threads.append(t) t.start() # 等待所有線程完成 for t in threads: t.join() print("All threads have finished.")
在這個(gè)例子中創(chuàng)建了10個(gè)線程,但是通過(guò)信號(hào)量限制了同時(shí)訪問(wèn)共享資源的線程數(shù)最多為3個(gè)。每個(gè)線程在工作前都會(huì)嘗試獲取信號(hào)量的許可,如果信號(hào)量的值大于0,則獲取許可并開(kāi)始工作;如果信號(hào)量的值為0,則線程會(huì)阻塞等待,直到有其他線程釋放許可。每個(gè)線程完成工作后會(huì)釋放其持有的信號(hào)量許可,這樣其他等待的線程就可以獲取許可并開(kāi)始工作。
總結(jié)
到此這篇關(guān)于Python并發(fā)執(zhí)行的幾種實(shí)現(xiàn)方法的文章就介紹到這了,更多相關(guān)Python并發(fā)執(zhí)行實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python實(shí)現(xiàn)大戰(zhàn)外星人小游戲?qū)嵗a
這篇文章主要介紹了python實(shí)現(xiàn)大戰(zhàn)外星人小游戲,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12Python urllib request模塊發(fā)送請(qǐng)求實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了Python urllib request模塊發(fā)送請(qǐng)求實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12python中的psutil模塊詳解(cpu、內(nèi)存、磁盤(pán)情況、結(jié)束指定進(jìn)程)
這篇文章主要介紹了python中的psutil(cpu、內(nèi)存、磁盤(pán)情況、結(jié)束指定進(jìn)程),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04Python使用multiprocessing實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的分布式作業(yè)調(diào)度系統(tǒng)
mutilprocess像線程一樣管理進(jìn)程,這個(gè)是mutilprocess的核心,他與threading很是相像,對(duì)多核CPU的利用率會(huì)比threading好的多,通過(guò)本文給大家介紹Python使用multiprocessing實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的分布式作業(yè)調(diào)度系統(tǒng),需要的朋友參考下2016-03-03解決python報(bào)錯(cuò):AttributeError:?'ImageDraw'?object?h
這篇文章主要給大家介紹了關(guān)于解決python報(bào)錯(cuò):AttributeError:?'ImageDraw'?object?has?no?attribute?'textbbox'的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01Python實(shí)現(xiàn)簡(jiǎn)單http服務(wù)器
這篇文章主要為大家詳細(xì)介紹了Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單http服務(wù)器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04python小程序之4名牌手洗牌發(fā)牌問(wèn)題解析
這篇文章主要為大家詳細(xì)介紹了python小程序之4名牌手洗牌發(fā)牌問(wèn)題,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05Python網(wǎng)絡(luò)爬蟲(chóng)之獲取網(wǎng)絡(luò)數(shù)據(jù)
本文介紹了Python中用于獲取網(wǎng)絡(luò)數(shù)據(jù)的重要工具之一——Requests庫(kù),詳細(xì)講解了Requests庫(kù)的基本使用方法、請(qǐng)求方法、請(qǐng)求頭、請(qǐng)求參數(shù)、Cookies、Session等內(nèi)容,并結(jié)合實(shí)例代碼展示了Requests庫(kù)的應(yīng)用場(chǎng)景2023-04-04python使用folium庫(kù)繪制地圖點(diǎn)擊框
這篇文章主要為大家詳細(xì)介紹了python使用folium庫(kù)繪制地圖點(diǎn)擊框,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09