在python守护进程中使用多处理模块时,我遇到以下错误(使用 python-daemon ):
Traceback (most recent call last): File "/usr/local/lib/python2.6/atexit.py", line 24, in _run_exitfuncs func(*targs, **kargs) File "/usr/local/lib/python2.6/multiprocessing/util.py", line 262, in _exit_function for p in active_children(): File "/usr/local/lib/python2.6/multiprocessing/process.py", line 43, in active_children _cleanup() File "/usr/local/lib/python2.6/multiprocessing/process.py", line 53, in _cleanup if p._popen.poll() is not None: File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 106, in poll pid, sts = os.waitpid(self.pid, flag) OSError: [Errno 10] No child processes
守护进程(父进程)生成许多进程(子进程),然后定期轮询进程以查看它们是否已完成。如果父进程检测到其中一个进程已完成,则会尝试重新启动该进程。正是在这一点上提出了上述异常。似乎一旦其中一个进程完成,涉及多处理模块的任何操作都将生成此异常。如果我在非守护程序python脚本中运行相同的代码,它将执行而不会出现任何错误。
修改
示例脚本
from daemon import runner
class DaemonApp(object):
def __init__(self, pidfile_path, run):
self.pidfile_path = pidfile_path
self.run = run
self.stdin_path = '/dev/null'
self.stdout_path = '/dev/tty'
self.stderr_path = '/dev/tty'
def run():
import multiprocessing as processing
import time
import os
import sys
import signal
def func():
print 'pid: ', os.getpid()
for i in range(5):
print i
time.sleep(1)
process = processing.Process(target=func)
process.start()
while True:
print 'checking process'
if not process.is_alive():
print 'process dead'
process = processing.Process(target=func)
process.start()
time.sleep(1)
# uncomment to run as daemon
app = DaemonApp('/root/bugtest.pid', run)
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()
#uncomment to run as regular script
#run()
答案 0 :(得分:6)
您的问题是守护程序和多处理模块之间的冲突,特别是在处理SIGCLD(子进程终止)信号时。守护进程在启动时将SIGCLD设置为SIG_IGN,至少在Linux上,会导致终止的子进程立即被收获(而不是在父进程调用wait()之前成为僵尸)。但是多处理的is_alive测试调用wait()来查看进程是否处于活动状态,如果进程已被收集,则该进程失败。
最简单的解决方案就是将SIGCLD设置回SIG_DFL(默认行为 - 忽略信号并让父查询终止子进程):
def run():
# ...
signal.signal(signal.SIGCLD, signal.SIG_DFL)
process = processing.Process(target=func)
process.start()
while True:
# ...
答案 1 :(得分:4)
忽略SIGCLD
也会导致subprocess
模块出现问题,因为该模块中存在错误(issue 1731717,截至2011-09-21仍然有效)。
此行为在python-daemon
库的version 1.4.8中得到解决;它现在省略了SIGCLD
的默认摆弄,因此不再与其他标准库模块进行这种令人不快的交互。
答案 2 :(得分:0)
我认为不久之前有一个修复程序放入trunk和2.6 maint,这应该有帮助,你可以尝试在python-trunk或最新的2.6-maint svn中运行你的脚本吗?我没有提取错误信息
答案 3 :(得分:0)
看起来你的错误即将发生在你的过程的最后 - 你的线索就在追溯的最开始,我引用了......:
File "/usr/local/lib/python2.6/atexit.py", line 24, in _run_exitfuncs
func(*targs, **kargs)
如果atexit._run_exitfuncs
正在运行,这清楚地表明您自己的进程正在终止。因此,错误本身在某种意义上是一个小问题 - 只是从multiprocessing
模块注册为从您的进程“退出”运行的某个函数。真正有趣的问题是,为什么你的主要流程正在退出?我认为这可能是由于一些未被捕获的异常:尝试设置异常挂钩并显示丰富的诊断信息,然后由于多处理注册为退出运行而导致的OTHER异常丢失...
答案 4 :(得分:0)
我也在使用带有Python 2.6的RHEL 5.3下的celery分布式任务管理器。我的追溯看起来有点不同,但错误相同:
File "/usr/local/lib/python2.6/multiprocessing/pool.py", line 334, in terminate
self._terminate()
File "/usr/local/lib/python2.6/multiprocessing/util.py", line 174, in __call__
res = self._callback(*self._args, **self._kwargs)
File "/usr/local/lib/python2.6/multiprocessing/pool.py", line 373, in _terminate_pool
p.terminate()
File "/usr/local/lib/python2.6/multiprocessing/process.py", line 111, in terminate
self._popen.terminate()
File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 136, in terminate
if self.wait(timeout=0.1) is None:
File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 121, in wait
res = self.poll()
File "/usr/local/lib/python2.6/multiprocessing/forking.py", line 106, in poll
pid, sts = os.waitpid(self.pid, flag)
OSError: [Errno 10] No child processes
非常令人沮丧..我现在正在通过pdb运行代码,但还没有发现任何内容。
答案 5 :(得分:0)
原始样本脚本具有“导入信号”但不使用信号。但是,我有一个脚本导致此错误消息,这是由于我的信号处理,所以我将在这里解释,以防其他人发生了什么。在信号处理程序中,我正在处理进程(例如创建新进程)。显然这不起作用,所以我在处理程序中停止这样做并修复了错误。 (注意:sleep()函数在信号处理后唤醒,因此如果您需要使用进程执行操作,这可以作为处理信号的替代方法)