2013-11-15 53 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