多進(jìn)程是什么
多進(jìn)程指的是操作系統(tǒng)同時(shí)支持多個(gè)處理器的能力岛蚤。在支持多任務(wù)操作系統(tǒng)中,一個(gè)應(yīng)用程序會被分解成多個(gè)獨(dú)立運(yùn)行的較小的程序恐仑。操作系統(tǒng)會將這些線程分配到多核處理器择同,以提升系統(tǒng)性能。
為什么需要多進(jìn)程
假設(shè)我們的計(jì)算機(jī)只有一個(gè)單核的處理器轨奄,然后同時(shí)被分配了幾個(gè)任務(wù)孟害,那么它就不得不在各個(gè)任務(wù)中來回切換,短暫地執(zhí)行其中一個(gè)任務(wù)戚绕,然后中斷纹坐,然后短暫地執(zhí)行下一個(gè)任務(wù),以保持所有的進(jìn)程都在運(yùn)行。這就像一個(gè)廚師在做面條耘子,切幾秒鐘菜果漾,跑去揉幾下面,再趕緊查看下湯谷誓。
所以同時(shí)需要完成的任務(wù)越多绒障,同時(shí)跟蹤所有的任務(wù)就越困難。這就是多進(jìn)程的必要性捍歪,也是多核處理器的威力所在户辱。
一個(gè)支持多進(jìn)程的操作系統(tǒng)可以做到:
- 同時(shí)指揮多個(gè)CPU,即擁有一個(gè)以上的CPU的計(jì)算機(jī)
- 指揮多核CPU糙臼,即擁有兩個(gè)及以上的獨(dú)立處理單元的CPU
這樣庐镐,計(jì)算機(jī)就可以輕松地同時(shí)執(zhí)行多個(gè)任務(wù),每個(gè)任務(wù)都可以使用自己的處理器变逃。就像之前舉的例子必逆,現(xiàn)在廚房里有專門的揉面師傅,備菜師傅揽乱,煮湯師傅名眉。事情就變得輕松多了。
用Python執(zhí)行多進(jìn)程
學(xué)習(xí)Python的優(yōu)勢之一就是它擁有海量的第三方模塊凰棉。今天我們再來介紹一個(gè)能幫你輕松完成多進(jìn)程并行的模塊:
multiprocessing
multiprocessing模塊支持使用類似于threading模塊的API生成進(jìn)程损拢。multiprocessing模塊提供了本地和遠(yuǎn)程計(jì)算機(jī)的并行處理能力,并且通過使用創(chuàng)建子進(jìn)程撒犀,有效地避開了全局解釋器鎖(GIL)福压。因此,multiprocessing模塊允許程序員充分利用機(jī)器上的多個(gè)處理器绘证。目前隧膏,它可以在Unix和Windows上運(yùn)行。
multiprocessing的模塊的API非常簡單直觀嚷那,可以讓新手迅速上手在多個(gè)進(jìn)程之間劃分工作胞枕。我們現(xiàn)在看一個(gè)簡單的例子:
# importing the multiprocessing module
import multiprocessing
def print_cube(num):
print("Cube: {}".format(num * num * num))
def print_square(num):
print("Square: {}".format(num * num))
if __name__ == "__main__":
# creating processes
p1 = multiprocessing.Process(target=print_square, args=(10, ))
p2 = multiprocessing.Process(target=print_cube, args=(10, ))
# starting process 1&2
p1.start()
p2.start()
# wait until process 1&2 is finished
p1.join()
p2.join()
# both processes finished
print("Done!")
運(yùn)行結(jié)果是這樣的:
Square: 100
Cube: 1000
Done!
其實(shí)代碼的含義非常簡單了,首先我們導(dǎo)入了multiprocessing模塊魏宽,隨后定義了兩個(gè)函數(shù)腐泻,它們的功能分別是打印一個(gè)數(shù)的三次方和打印一個(gè)數(shù)的平方。
之后關(guān)鍵的步驟來了队询,要?jiǎng)?chuàng)建多個(gè)進(jìn)程派桩,首先需要?jiǎng)?chuàng)建Process類的對象。在這個(gè)例子中Process類接收了兩個(gè)參數(shù):
- target:在進(jìn)程中被執(zhí)行的函數(shù)
- args:向被執(zhí)行函數(shù)傳遞的參數(shù)
當(dāng)然蚌斩,進(jìn)程構(gòu)造函數(shù)還可以接受許多其他參數(shù)铆惑,我們之后會更詳細(xì)地介紹。在上面的例子中,我們創(chuàng)建了兩個(gè)具有不同目標(biāo)函數(shù)的進(jìn)程:
p1 = multiprocessing.Process(target=print_square, args=(10, ))
p2 = multiprocessing.Process(target=print_cube, args=(10, ))
隨后的start()
方法就是開始執(zhí)行p1员魏,p2兩個(gè)進(jìn)程丑蛤。在進(jìn)程開始執(zhí)行后,主程序仍然會繼續(xù)執(zhí)行撕阎。為了讓主程序暫停受裹,我們就使用了join()
方法。它的作用就是將主程序暫停虏束,直到等待p1和p2完成棉饶。一旦它們都完成了,再執(zhí)行之后的語句镇匀。
讓我們再舉一個(gè)例子照藻,來理解同一個(gè)腳本中運(yùn)行不同進(jìn)程的概念。在下面的例子中汗侵,我們打印運(yùn)行目標(biāo)函數(shù)的進(jìn)程ID:
# importing the multiprocessing module
import multiprocessing
import os
def worker1():
# printing process id
print("ID of process running worker1: {}".format(os.getpid()))
def worker2():
# printing process id
print("ID of process running worker2: {}".format(os.getpid()))
if __name__ == "__main__":
# printing main program process id
print("ID of main process: {}".format(os.getpid()))
# creating processes
p1 = multiprocessing.Process(target=worker1)
p2 = multiprocessing.Process(target=worker2)
# starting processes
p1.start()
p2.start()
# process IDs
print("ID of process p1: {}".format(p1.pid))
print("ID of process p2: {}".format(p2.pid))
# wait until processes are finished
p1.join()
p2.join()
# both processes finished
print("Both processes finished execution!")
# check if processes are alive
print("Process p1 is alive: {}".format(p1.is_alive()))
print("Process p2 is alive: {}".format(p2.is_alive()))
上面這個(gè)程序的輸出結(jié)果如下:
ID of main process: 28628
ID of process running worker1: 29305
ID of process running worker2: 29306
ID of process p1: 29305
ID of process p2: 29306
Both processes finished execution!
Process p1 is alive: False
Process p2 is alive: False
主python腳本有一個(gè)獨(dú)立的進(jìn)程ID岩梳,當(dāng)我們創(chuàng)建進(jìn)程對象p1和p2時(shí),multiprocessing模塊會生成具有不同進(jìn)程ID的新進(jìn)程晃择。os.getpid()
函數(shù)是用來獲取運(yùn)行當(dāng)前目標(biāo)函數(shù)的進(jìn)程的ID。上述輸出結(jié)果也可以看到也物,使用os.getpid()
獲取的進(jìn)程ID與通過進(jìn)程類的pid屬性獲得的ID是一致的宫屠。
上面的每個(gè)進(jìn)程都是獨(dú)立運(yùn)行的,并且擁有自己獨(dú)立的內(nèi)存空間滑蚯。
一旦目標(biāo)函數(shù)執(zhí)行完成浪蹂,進(jìn)程就會終止。在上面的程序中告材,我們使用了Process類的is_alive()
方法來檢查進(jìn)程是否仍然處于活動狀態(tài)坤次。
最后用下面的圖來幫助理解記憶新進(jìn)程與主Python腳本的不同之處:
這篇文章是對Python中的多進(jìn)程的一個(gè)初步介紹。接下來的幾篇文章將進(jìn)一步介紹多進(jìn)程相關(guān)知識斥赋。
敬請期待吧缰猴!