2013-11-15 49 views
4

我的同事要求我的幫助,他遇到了一個他正在使用的守護進程腳本的問題。他是有一個奇怪的錯誤涉及multiprocessing.Manager,我成功地再現與以下五類線:Python multiprocessing.manager和os.fork產生奇怪的行爲

import multiprocessing, os, sys 
mgr = multiprocessing.Manager() 
pid = os.fork() 
if pid > 0: 
    sys.exit(0) 

當在CentOS 6 Linux和Python 2.6中運行時,我收到以下錯誤:

Traceback (most recent call last): 
    File "/usr/lib64/python2.6/multiprocessing/util.py", line 235, in _run_finalizers 
    finalizer() 
    File "/usr/lib64/python2.6/multiprocessing/util.py", line 174, in __call__ 
    res = self._callback(*self._args, **self._kwargs) 
    File "/usr/lib64/python2.6/multiprocessing/managers.py", line 576, in _finalize_manager 
    if process.is_alive(): 
    File "/usr/lib64/python2.6/multiprocessing/process.py", line 129, in is_alive 
    assert self._parent_pid == os.getpid(), 'can only test a child process' 
AssertionError: can only test a child process 
Error in atexit._run_exitfuncs: 
Traceback (most recent call last): 
    File "/usr/lib64/python2.6/atexit.py", line 24, in _run_exitfuncs 
    func(*targs, **kargs) 
    File "/usr/lib64/python2.6/multiprocessing/util.py", line 269, in _exit_function 
    p.join() 
    File "/usr/lib64/python2.6/multiprocessing/process.py", line 117, in join 
    assert self._parent_pid == os.getpid(), 'can only join a child process' 
AssertionError: can only join a child process 
Error in sys.exitfunc: 
Traceback (most recent call last): 
    File "/usr/lib64/python2.6/atexit.py", line 24, in _run_exitfuncs 
    func(*targs, **kargs) 
    File "/usr/lib64/python2.6/multiprocessing/util.py", line 269, in _exit_function 
    p.join() 
    File "/usr/lib64/python2.6/multiprocessing/process.py", line 117, in join 
    assert self._parent_pid == os.getpid(), 'can only join a child process' 
AssertionError: can only join a child process 

我懷疑這個錯誤是由os.fork和multiprocessing.Manager之間的一些交互造成的,他應該使用多處理模塊來創建新的進程而不是os.fork。任何人都可以證實這一點和/或解釋發生了什麼?如果我的預感是正確的,爲什麼這是錯誤的地方使用os.fork?

+1

'Manager'總是創建一個處理共享內存的新進程,所以似乎有一些交互。現在我無法確切地告訴你爲什麼會發生這種情況,以及如何使用'os.fork'來解決這個問題。我必須同意,應該避免使用'os.fork',因爲它真的是*低級*。應該有一些使用'multiprocessing'的方法。 – Bakuriu

回答

2

問題是Manager創建一個進程,並試圖停止它在sys.exit。由於該過程的內存在分叉期間被複制(懶惰),所以父母和孩子都試圖停止該過程並等待它停止。但是,由於例外只提及父進程可以做到這一點。如果不使用os.fork,則使用multiprocessing.Process,這將產生一個新的過程,該過程不會嘗試關閉Manager,sys.exit