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