python多進程的理解 multiprocessing Process join run

最近看了下多進程。python

一種接近底層的實現方法是使用 os.fork()方法,fork出子進程。可是這樣作事有侷限性的。好比windows的os模塊裏面沒有 fork() 方法。linux

windows:。linux:windows

 

另外還有一個模塊:subprocess。這個沒整過,但從vamei的博客裏看到說也一樣有侷限性。dom

因此直接說主角吧 --- multiprocessing模塊。 multiprocessing模塊會在windows上時模擬出fork的效果,能夠實現跨平臺,因此大多數都使用multiprocessing。函數

下面給一段簡單的代碼,演示一下建立進程:spa

#encoding:utf-8
from multiprocessing import Process
import os, time, random

#線程啓動後實際執行的代碼塊
def r1(process_name):
    for i in range(5):
        print process_name, os.getpid()     #打印出當前進程的id
        time.sleep(random.random())
def r2(process_name): for i in range(5): print process_name, os.getpid() #打印出當前進程的id time.sleep(random.random()) if __name__ == "__main__": print "main process run..." p1 = Process(target=r1, args=('process_name1', )) #target:指定進程執行的函數,args:該函數的參數,須要使用tuple p2 = Process(target=r2, args=('process_name2', )) p1.start() #經過調用start方法啓動進程,跟線程差很少。 p2.start() #但run方法在哪呢?待會說。。。 p1.join() #join方法也頗有意思,尋思了一下午,終於理解了。待會演示。 p2.join() print "main process runned all lines..."

執行結果:線程

 

上面提到了兩個方法:runjoin3d

run:若是在建立Process對象的時候不指定target,那麼就會默認執行Process的run方法:code

#encoding:utf-8
from multiprocessing import Process
import os, time, random

def r():
    print 'run method'
    
if __name__ == "__main__":
        print "main process run..."
        #沒有指定Process的targt
        p1 = Process()
        p2 = Process()
        #若是在建立Process時不指定target,那麼執行時沒有任何效果。由於默認的run方法是判斷若是不指定target,那就什麼都不作
        #因此這裏手動改變了run方法
        p1.run = r
        p2.run = r
        
        p1.start()
        p2.start()
        p1.join()
        p2.join()
        print "main process runned all lines..."

另:python源碼裏,Process.run方法:對象

執行結果:

可見若是在實例化Process不指定target,就會執行默認的run方法。

 

還有一個join方法:

最上面演示的代碼中,在調用Process的start方法後,調用了兩次join方法。這個join方法是幹什麼的呢?

官方文檔的意思是:阻塞當前進程,直到調用join方法的那個進程執行完,再繼續執行當前進程。

 

好比仍是剛纔的代碼,只是把兩個join註釋掉了:

#encoding:utf-8
from multiprocessing import Process
import os, time, random

def r1(process_name):
    for i in range(5):
        print process_name, os.getpid()     #打印出當前進程的id
        time.sleep(random.random())
def r2(process_name):
    for i in range(5):
        print process_name, os.getpid()     #打印出當前進程的id
        time.sleep(random.random())

if __name__ == "__main__":
        print "main process run..."
        p1 = Process(target=r1, args=('process_name1', )) 
        p2 = Process(target=r2, args=('process_name2', )) 

        p1.start()
        p2.start()
 #p1.join()
#p2.join()
print "main process runned all lines..."

 執行結果:

 發現主進程不像以前那樣,等待兩個子進程執行完了,才繼續執行。而是啓動兩個進程後當即向下執行。

 

爲了深入理解,此次把p2的執行函數裏面睡眠時間調大,讓他多睡一會,而後保留p1的join,註釋掉p2的join,效果更明顯:

#encoding:utf-8
from multiprocessing import Process
import os, time, random

def r1(process_name):
    for i in range(5):
        print process_name, os.getpid()     #打印出當前進程的id
        time.sleep(random.random())
def r2(process_name):
    for i in range(5):
        print process_name, os.getpid()     #打印出當前進程的id
        time.sleep(random.random()*2)

if __name__ == "__main__":
        print "main process run..."
        p1 = Process(target=r1, args=('process_name1', )) 
        p2 = Process(target=r2, args=('process_name2', )) 

        p1.start()
        p2.start()
        p1.join()
        #p2.join()    
        print "main process runned all lines..."

執行結果:

發現主線程只是等待p1完成了,就會向下執行,而不會等待p2是否完成。

 因此使用多進程的常規方法是,先依次調用start啓動進程,再依次調用join要求主進程等待子進程的結束。

 

然而爲何要先依次調用start再調用join,而不是start完了就調用join呢,以下:

由:

p1.start()
p2.start()
p1.join()

改成:

p1.start()
p1.join()
p2.start()

執行效果:

 發現是先執行完p1,再執行主線程,最後纔開始p2。

今天上午一直困惑這個事,如今終於明白了。join是用來阻塞當前線程的,p1.start()以後,p1就提示主線程,須要等待p1結束才向下執行,那主線程就乖乖的等着啦,天然沒有執行p2.start()這一句啦,固然就變成了圖示的效果了。

相關文章
相關標籤/搜索