python多進程的理解 multiprocessing Process join run


最近看了下多進程。

一種接近底層的實現方法是使用 os.fork()方法,fork出子進程。但是這樣做事有局限性的。比如windows的os模塊里面沒有 fork() 方法。

windows:。linux:

 

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

所以直接說主角吧 --- 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..."

執行結果:

 

上面提到了兩個方法:runjoin

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

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM