2014-07-22 98 views

回答

8

當使用multiprocessing.Pool,如果池中崩潰的子進程的一個,你會不會在所有的通知,和一個新的進程將立即啓動,以取代其位置:

>>> import multiprocessing 
>>> p = multiprocessing.Pool() 
>>> p._processes 
4 
>>> p._pool 
[<Process(PoolWorker-1, started daemon)>, <Process(PoolWorker-2, started daemon)>, <Process(PoolWorker-3, started daemon)>, <Process(PoolWorker-4, started daemon)>] 
>>> [proc.pid for proc in p._pool] 
[30760, 30761, 30762, 30763] 

然後在另一個窗口:

[email protected]:~$ kill 30763 

回到池:

>>> [proc.pid for proc in p._pool] 
[30760, 30761, 30762, 30767] # New pid for the last process 

你可以像沒有任何事情一樣繼續使用池。但是,死亡子進程在其死亡時正在運行的任何工作項目將不會完成或重新啓動,而是而不是。如果您正在運行依靠該工作項目完成的阻止mapapply調用,該調用可能會無限期地掛起。有一個bug filed for this,但該問題僅在concurrent.futures.ProcessPoolExecutor中修正,而不是在multiprocessing.Pool中修復。從Python 3.3開始,如果子進程被終止,ProcessPoolExecutor將引發BrokenProcessPool異常,並且不允許進一步使用該池。可悲的是,multiprocessing沒有得到這個增強。現在,如果您想防止由於子進程崩潰而導致永久性阻止池呼叫,則必須使用ugly workarounds

注意:以上僅適用於處理池中實際上崩潰,這意味着該過程完全死亡。如果一個子進程拋出一個異常,當您嘗試檢索工作項目的結果將被向上傳播的父進程:

>>> def f(): raise Exception("Oh no") 
... 
>>> pool = multiprocessing.Pool() 
>>> result = pool.apply_async(f) 
>>> result.get() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/python2.7/multiprocessing/pool.py", line 528, in get 
    raise self._value 
Exception: Oh no 

當使用multiprocessing.Process直接,進程對象將顯示該進程已與一個非零退出代碼退出如果它崩潰:

>>> def f(): time.sleep(30) 
... 
>>> p = multiprocessing.Process(target=f) 
>>> p.start() 
>>> p.join() # Kill the process while this is blocking, and join immediately ends 
>>> p.exitcode 
-15 

如果有異常的上升的行爲是類似的:

from multiprocessing import Process 

def f(x): 
    raise Exception("Oh no") 

if __name__ == '__main__': 
    p = Process(target=f) 
    p.start() 
    p.join() 
    print(p.exitcode) 
    print("done") 

輸出:

Process Process-1: 
Traceback (most recent call last): 
    File "/usr/lib/python3.2/multiprocessing/process.py", line 267, in _bootstrap 
    self.run() 
    File "/usr/lib/python3.2/multiprocessing/process.py", line 116, in run 
    self._target(*self._args, **self._kwargs) 
TypeError: f() takes exactly 1 argument (0 given) 
1 
done 

正如你所看到的,從孩子回溯印,但它不會影響主進程,這是能夠證明孩子的exitcode的exceution是1