1. 程式人生 > >python多程序的理解 multiprocessing Process join run

python多程序的理解 multiprocessing Process join run

multiprocessing模組。 multiprocessing模組會在windows上時模擬出fork的效果,可以實現跨平臺,所以大多數都使用multiprocessing。

下面給一段簡單的程式碼,演示一下建立程序:

#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..."

執行結果:


 

上面提到了兩個方法:run 和join

run:如果在建立Process物件的時候不指定target,那麼就會預設執行Process的run方法:

#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()這一句啦,當然就變成了圖示的效果了。