Python多进程怎么应用
這篇文章主要講解了“Python多進程怎么應用”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Python多進程怎么應用”吧!
并行和串行計算
想象一下,你有一個巨大的問題要解決,而你獨自一人。你需要計算八個不同數字的平方根。你是做什么的?你沒有太多選擇。從第一個數字開始,然后計算結果。然后,你繼續和其他人。
如果你有三個擅長數學的朋友愿意幫助你呢?他們每個人都會計算兩個數字的平方根,你的工作會更容易,因為工作量在你的朋友之間平均分配。這意味著你的問題將更快地得到解決。
好了,一切都清楚了嗎?在這些示例中,每個朋友代表CPU的核心。在第一個示例中,整個任務由你依次解決。這稱為串行計算。在第二個示例中,由于你總共使用了四個內核,因此你使用的是并行計算。并行計算涉及使用并行進程或在處理器的多個核之間劃分的進程。
并行編程模型
我們已經確定了什么是并行編程,但我們如何使用它?我們之前說過,并行計算涉及在處理器的多個核心之間執行多個任務,這意味著這些任務是同時執行的。在進行并行化之前,你應該考慮幾個問題。例如,是否有其他優化可以加快我們的計算速度?
現在,讓我們理所當然地認為并行化是最適合的解決方案。并行計算主要有三種模式:
-
完全平行。任務可以獨立運行,不需要相互通信。
-
共享內存并行。進程(或線程)需要通信,因此它們共享一個全局地址空間。
-
消息傳遞。進程需要在需要時共享消息。
在本文中,我們將說明第一個模型,它也是最簡單的。
Python多進程:Python中基于進程的并行性
在 Python 中實現并行性的一種方法是使用multiprocessing 模塊。multiprocessing模塊允許你創建多個進程,每個進程都有自己的 Python 解釋器。因此,Python 多進程實現了基于進程的并行。
你可能聽說過其他庫,比如threading,它也是Python內置的,但它們之間有著重要的區別。multiprocessing模塊創建新進程,而threading創建新線程。
使用多進程的好處
你可能會問,“為什么選擇多進程?”多進程可以通過并行而不是按順序運行多個任務來顯著提高程序的效率。一個類似的術語是多線程,但它們是不同的。
進程是加載到內存中運行的程序,不與其他進程共享其內存。線程是進程中的一個執行單元。多個線程在一個進程中運行,并相互共享進程的內存空間。
Python的全局解釋器鎖(GIL)只允許在解釋器下一次運行一個線程,這意味著如果需要Python解釋器,你將無法享受多線程的性能優勢。這就是在Python中多進程比線程更占優勢的原因。多個進程可以并行運行,因為每個進程都有自己的解釋器,執行分配給它的指令。此外,操作系統將在多個進程中查看你的程序,并分別對它們進行調度,即,你的程序在總的計算機資源中占有更大的份額。因此,當程序受到CPU限制時,多進程速度更快。在程序中有大量I/O的情況下,線程可能更高效,因為大多數時候,程序都在等待I/O完成。然而,多進程通常效率更高,因為它同時運行。
以下是多進程的一些好處:
-
在處理高CPU密集型任務時更好地使用CPU
-
與線程相比,對子線程的控制更多
-
易于編碼
第一個優點與性能有關。由于多進程創建了新的進程,你可以通過在其他內核之間劃分任務來更好地利用CPU的計算能力。現在大多數處理器都是多核處理器,如果你優化代碼,可以通過并行計算節省時間。
第二個優點是多線程處理的替代方案。線程不是進程,這有其后果。如果你創建了一個線程,那么像處理正常進程一樣終止它甚至中斷它是很危險的。由于多進程和多線程之間的比較不在本文的范圍內,后續我會單獨寫一篇來講講多進程和多線程的區別。
多進程的第三個優點是它很容易實現,因為你嘗試處理的任務適合并行編程。
Python多進程入門
我們終于準備好編寫一些 Python 代碼了!
我們將從一個非常基本的示例開始,我們將使用它來說明 Python 多進程的核心方面。在此示例中,我們將有兩個進程:
-
parent經常。只有一個父進程,它可以有多個子進程。 -
child進程。這是由父進程產生的。每個子進程也可以有新的子進程。
我們將使用該child過程來執行某個函數。這樣,parent可以繼續執行。
一個簡單的 Python多進程示例
這是我們將用于此示例的代碼:
frommultiprocessingimportProcess
defbubble_sort(array):
check=True
whilecheck==True:
check=False
foriinrange(0,len(array)-1):
ifarray[i]>array[i+1]:
check=True
temp=array[i]
array[i]=array[i+1]
array[i+1]=temp
print("Arraysorted:",array)
if__name__=='__main__':
p=Process(target=bubble_sort,args=([1,9,4,5,2,6,8,4],))
p.start()
p.join()
在這個片段中,我們定義了一個名為bubble_sort(array)。這個函數是冒泡排序算法的一個非常簡單的實現。如果你不知道它是什么,請不要擔心,因為它并不重要。要知道的關鍵是它是一個可以實現某個功能的函數。
進程類
從multiprocessing,我們導入類Process。此類表示將在單獨進程中運行的活動。事實上,你可以看到我們已經傳遞了一些參數:
-
target=bubble_sort,意味著我們的新進程將運行該bubble_sort函數 -
args=([1,9,4,52,6,8,4],),這是作為參數傳遞給目標函數的數組
一旦我們創建了 Process 類的實例,我們只需要啟動該進程。這是通過編寫p.start()完成的。此時,該進程開始。
在我們退出之前,我們需要等待子進程完成它的計算。該join()方法等待進程終止。
在這個例子中,我們只創建了一個子進程。正如你可能猜到的,我們可以通過在Process類中創建更多實例來創建更多子進程。
進程池類
如果我們需要創建多個進程來處理更多 CPU 密集型任務怎么辦?我們是否總是需要明確地開始并等待終止?這里的解決方案是使用Pool類。
Pool類允許你創建一個工作進程池,在下面的示例中,我們將研究如何使用它。這是我們的新示例:
frommultiprocessingimportPool
importtime
importmath
N=5000000
defcube(x):
returnmath.sqrt(x)
if__name__=="__main__":
withPool()aspool:
result=pool.map(cube,range(10,N))
print("Programfinished!")
在這個代碼片段中,我們有一個cube(x)函數,它只接受一個整數并返回它的平方根。很簡單,對吧?
然后,我們創建一個Pool類的實例,而不指定任何屬性。默認情況下,Pool類為每個 CPU 核心創建一個進程。接下來,我們使用幾個參數運行map方法。
map方法將cube函數應用于我們提供的可迭代對象的每個元素——在本例中,它是從10到N的每個數字的列表。
這樣做的最大優點是列表上的計算是并行進行的!
joblib
包joblib是一組使并行計算更容易的工具。它是一個用于多進程的通用第三方庫。它還提供緩存和序列化功能。要安裝joblib包,請在終端中使用以下命令:
pipinstalljoblib
我們可以將之前的示例轉換為以下示例以供使用joblib:
fromjoblibimportParallel,delayed
defcube(x):
returnx**3
start_time=time.perf_counter()
result=Parallel(n_jobs=3)(delayed(cube)(i)foriinrange(1,1000))
finish_time=time.perf_counter()
print(f"Programfinishedin{finish_time-start_time}seconds")
print(result)
事實上,直觀地看到它的作用。delayed()函數是另一個函數的包裝器,用于生成函數調用的“延遲”版本。這意味著它在被調用時不會立即執行函數。
然后,我們多次調用delayed函數,并傳遞不同的參數集。例如,當我們將整數1賦予cube函數的延遲版本時,我們不計算結果,而是分別為函數對象、位置參數和關鍵字參數生成元組(cube, (1,), {})。
我們使用Parallel()創建了引擎實例。當它像一個以元組列表作為參數的函數一樣被調用時,它將實際并行執行每個元組指定的作業,并在所有作業完成后收集結果作為列表。在這里,我們創建了n_jobs=3的Parallel()實例,因此將有三個進程并行運行。
我們也可以直接編寫元組。因此,上面的代碼可以重寫為:
result=Parallel(n_jobs=3)((cube,(i,),{})foriinrange(1,1000))
使用joblib的好處是,我們可以通過簡單地添加一個附加參數在多線程中運行代碼:
result=Parallel(n_jobs=3,prefer="threads")(delayed(cube)(i)foriinrange(1,1000))
這隱藏了并行運行函數的所有細節。我們只是使用與普通列表理解沒有太大區別的語法。
充分利用 Python多進程
創建多個進程并進行并行計算不一定比串行計算更有效。對于 CPU 密集度較低的任務,串行計算比并行計算快。因此,了解何時應該使用多進程非常重要——這取決于你正在執行的任務。
為了讓你相信這一點,讓我們看一個簡單的例子:
frommultiprocessingimportPool
importtime
importmath
N=5000000
defcube(x):
returnmath.sqrt(x)
if__name__=="__main__":
#firstway,usingmultiprocessing
start_time=time.perf_counter()
withPool()aspool:
result=pool.map(cube,range(10,N))
finish_time=time.perf_counter()
print("Programfinishedin{}seconds-usingmultiprocessing".format(finish_time-start_time))
print("---")
#secondway,serialcomputation
start_time=time.perf_counter()
result=[]
forxinrange(10,N):
result.append(cube(x))
finish_time=time.perf_counter()
print("Programfinishedin{}seconds".format(finish_time-start_time))
此代碼段基于前面的示例。我們正在解決同樣的問題,即計算N個數的平方根,但有兩種方法。第一個涉及 Python 進程的使用,而第二個不涉及。我們使用time庫中的perf_counter()方法來測量時間性能。
在我的電腦上,我得到了這個結果:
>pythoncode.py Programfinishedin1.6385094seconds-usingmultiprocessing --- Programfinishedin2.7373942999999996seconds
如你所見,相差不止一秒。所以在這種情況下,多進程更好。
讓我們更改代碼中的某些內容,例如N的值。 讓我們把它降低到N=10000,看看會發生什么。
這就是我現在得到的:
>pythoncode.py Programfinishedin0.3756742seconds-usingmultiprocessing --- Programfinishedin0.005098400000000003seconds
發生了什么?現在看來,多進程是一個糟糕的選擇。為什么?
與解決的任務相比,在進程之間拆分計算所帶來的開銷太大了。你可以看到在時間性能方面有多大差異。
總結
以上是生活随笔為你收集整理的Python多进程怎么应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: easypoi 多sheet导入_快速O
- 下一篇: 区域显示触发_高科技产业园发展 带动海淀