多進程
在Linux系統(tǒng)下,有一個非常特殊的函數(shù),fork()。它調(diào)用一次,返回兩次,操作系統(tǒng)自動把當前進程(父進程)復(fù)制了一份(子進程),然后分別在父進程和子進程內(nèi)返回。子進程永遠返回0,父進程返回子進程的ID。經(jīng)過這樣做,父進程就能fork出很多子進程,并可以記錄下子進程的ID號了,子進程可以通過getppid()來獲取父進程ID。fork()僅在Unix/Linux下使用,windows則不行。 所以,在Python中,存在一個跨平臺的包mutiprocessing,通過引入包中的Process類,就可以創(chuàng)建多進程程序了,可以創(chuàng)建一個進程p=Process(target=func,args=(*,)),然后利用p.start()及p.join()來執(zhí)行了。以上的join()方法可以等待子進程結(jié)束后才往下執(zhí)行,通常用于進程間同步。 另外,可以用進程池的方式,例如p=Pool(n),然后p.apply_async(func,args),這里可以使用n種不同的參數(shù)傳入,建立不同的進程。用這種方式時,在調(diào)用join()方法前,要先調(diào)用close()方法,使得不能再添加新進程。 mutiprocessing包里提供了Queue、Pipe等多種進程間通信的方法??梢灾苯右?code>Queue類,然后實例化一個對象。則不同的進程可以使用put方法發(fā)信息,同時可以使用get方法取信息。
多線程
多個任務(wù)可以創(chuàng)建多個進程來完成,同時也可以創(chuàng)建多個線程來完成,線程是操作系統(tǒng)直接的執(zhí)行單元。 Python含有threading這個高級模塊,要啟動一個線程,就是把一個函數(shù)傳出并創(chuàng)建Thread實例,然后調(diào)用start()方法開始執(zhí)行,例如t=threading.Thread(target=func,name=*),注意這里的name屬性,它是給線程命名的,缺省值為Thread-1···。要注意的是,剛才說了,任何一個進程都含有一個線程,而這個主線程則執(zhí)行著我們編寫的程序,可以調(diào)用threading.current_thread().name來查看它,它的名字就叫MainThread。 在多線程編程中,有一個最大的問題就在于進程內(nèi)的資源被各個線程所共享,進程內(nèi)任何變量都可以被任何一個線程修改,因此,線程之間若去修改同一個變量,則可能導(dǎo)致程序Bug。所以,引入了鎖機制。 當某個線程去修改某個變量時,可以在變量所在的方法內(nèi)加一把鎖,使得其他線程不能同時執(zhí)行該方法,只有釋放了鎖后,其他線程才能去獲得鎖并獲得修改權(quán)。創(chuàng)建一個鎖是通過lock=threading.Lock()來實現(xiàn)的,可以使用try···finally···語句,在try之前使用lock.acquire()獲得鎖,然后在try語句里面修改變量,然后在finally語句里加lock.release()來保證鎖一定被釋放,避免成為一個死鎖。
區(qū)別于聯(lián)系
多進程的優(yōu)點是穩(wěn)定性好,一個子進程崩潰了,不會影響主進程以及其余進程。但是缺點是創(chuàng)建進程的代價非常大,因為操作系統(tǒng)要給每個進程分配固定的資源,并且,操作系統(tǒng)對進程的總數(shù)會有一定的限制,若進程過多,操作系統(tǒng)調(diào)度都會存在問題,會造成假死狀態(tài)。多線程優(yōu)點是效率較高一些,但是致命的缺點是任何一個線程崩潰都可能造成整個進程的崩潰,因為它們共享了進程的內(nèi)存資源池。 對于任務(wù)數(shù)來說,無論是多進程或者多線程,都不能太多。因為操作系統(tǒng)在切換任務(wù)時,會有一系列的保護現(xiàn)場措施,這要花費相當?shù)南到y(tǒng)資源,若任務(wù)過多,則大部分資源都被用做干這些了,結(jié)果就是所有任務(wù)都做不好,所以操作系統(tǒng)會限制進程的數(shù)量。 另外,考慮計算密集型及IO密集型應(yīng)用程序。對于計算密集型,多任務(wù)勢必造成資源浪費。對于IO密集型,因為IO速度遠低于CPU計算速度,所以使用多任務(wù)方式可以大大增大程序運行效率。