2014-12-05 83 views
0

我是Python和多處理的新手。我想批量轉換一堆文件,所以我想我會嘗試多處理。 Pool和map()概念看起來很簡單,但似乎不起作用。我已經將它縮減到了下面的測試程序,但其要點是:它會經歷4次迭代(池中的每個進程)並在此之後掛起。以下是測試代碼:Pool.map在4次迭代後掛起

import multiprocessing, logging 
import os 
import sys 

mpl = multiprocessing.log_to_stderr() 
mpl.setLevel(logging.INFO) 

def chill(t): 
    cmd = '/bin/sleep' 
    args = (cmd,str(t)) 
    print >>sys.stderr, os.getpid(), args 
    os.execv(cmd, args) 

if __name__ == "__main__" : 
    times = [ 1 ] * 100 
    pool = multiprocessing.Pool(1) # change this for more processes 
    pool.map(chill, times) 
    pool.close() 
    pool.join() 

當我運行它時,它在第4次迭代後掛起。增加進程數量只會使進程數量增加4倍。這個「4」有什麼神奇的,我做錯了什麼?

+1

'os.execv'替換子進程後。你不想這樣做。嘗試'subprocess.call(['/ bin/sleep',str(t)])''。 – tdelaney 2014-12-05 01:50:50

+0

但是第一次通話後它會死掉,不是嗎? – Groot 2014-12-05 02:21:00

+0

我不確定,可能有一些恢復協議。 – tdelaney 2014-12-05 03:33:00

回答

0

問題是os.execv取代了子進程,因此父子之間的常規握手丟失了。 Pool.map()發送參數以塊處理。如果進程意外退出,mp重新啓動進程併發送另一個塊。您可能已經發現多處理模塊中存在一個錯誤,因爲它會繼續發送數據以處理此異常情況,然後掛起等待永遠不會到達的任務完成。

解決方案是使用函數(如subprocess.call)來完成要運行的代碼的完整分支和執行。這樣可以讓孩子的過程保持完整,並且能夠將結果傳遞給父母。

通過對測試程序進行一些更改,可以更清楚地看到問題。

import multiprocessing, logging 
import os 
import sys 
import subprocess as subp 

mpl = multiprocessing.log_to_stderr() 
mpl.setLevel(logging.INFO) 

def chill(args): 
    i, t = args 
    cmd = '/bin/sleep' 
    args = (cmd,str(t)) 
    print >>sys.stderr, i, os.getpid(), args 
    os.execv(cmd, args) 
# subp.call(['/bin/sleep', str(t)]) 

if __name__ == "__main__" : 
    times = [(i,1) for i in range(100)] 
    pool = multiprocessing.Pool(1) # change this for more processes 
    pool.map(chill, times) 
    pool.close() 
    pool.join() 

地圖已經打破了工作分成4塊,然後掛在最後一個

[INFO/PoolWorker-1] child process calling self.run() 
0 9204 ('/bin/sleep', '1') 
[INFO/PoolWorker-2] child process calling self.run() 
25 9208 ('/bin/sleep', '1') 
[INFO/PoolWorker-3] child process calling self.run() 
50 9209 ('/bin/sleep', '1') 
[INFO/PoolWorker-4] child process calling self.run() 
75 9210 ('/bin/sleep', '1') 
[INFO/PoolWorker-5] child process calling self.run() 
+0

我是Python的新手,但是我認爲「多處理」會做fork/join(和「pool.join()」)似乎會加強這種印象。如果它沒有執行fork/join,那麼execv()會導致問題是有道理的。但是這4個子進程讓我陷入了一個循環;因爲它似乎工作,我不認爲execv()是一個問題 – Groot 2014-12-05 17:57:58

+0

在Linux中,多處理做了一個分叉來創建其子。問題是你做了一個沒有額外分支的exec,所以孩子的multiprocessing.Pool協議丟失了。在我看來,多處理父母應該拋開一個例外,因爲從孩子的角度來看,這個孩子已經完全崩潰了。否則,我們只能猜測。 – tdelaney 2014-12-05 18:13:53