我为这个问题提出了一个问题,但没有得到足够彻底的答案来解决这个问题(很可能是因为在解释我的问题时缺乏严谨性,这正是我试图纠正的):python多处理守护进程中的僵尸进程
我正在尝试实现一个python守护进程,该守护进程使用一个工作线程池来使用Popen
执行命令。我从中借用了基本守护进程http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
我只更改了init
、daemonize
(或者同样更改了start
)和stop
方法。以下是对init
方法的更改:
def __init__(self, pidfile):
#, stdin='/dev/null', stdout='STDOUT', stderr='STDOUT'):
#self.stdin = stdin
#self.stdout = stdout
#self.stderr = stderr
self.pidfile = pidfile
self.pool = Pool(processes=4)
我并没有设置stdin、stdout和stderr,以便使用print语句调试代码。此外,我曾尝试将这个游泳池转移到几个地方,但这是唯一一个不会产生异常的地方。
以下是对daemonize
方法的更改:
def daemonize(self):
...
# redirect standard file descriptors
#sys.stdout.flush()
#sys.stderr.flush()
#si = open(self.stdin, 'r')
#so = open(self.stdout, 'a+')
#se = open(self.stderr, 'a+', 0)
#os.dup2(si.fileno(), sys.stdin.fileno())
#os.dup2(so.fileno(), sys.stdout.fileno())
#os.dup2(se.fileno(), sys.stderr.fileno())
print self.pool
...
同样的事情,我并没有重定向io以便调试。使用此处的打印以便我可以检查池的位置。
stop
方法改变:
def stop(self):
...
# Try killing the daemon process
try:
print self.pool
print "closing pool"
self.pool.close()
print "joining pool"
self.pool.join()
print "set pool to None"
self.pool = None
while 1:
print "kill process"
os.kill(pid, SIGTERM)
...
这里的想法是,我不仅需要停止这个过程,还需要清理水池。self.pool = None
只是一个随机的尝试来解决没有起作用的问题。起初,我认为这是僵尸孩子的问题,当我在带有os.kill(pid, SIGTERM)
的while循环中有self.pool.close()
和self.pool.join()
时,就会出现这种问题。这是在我决定开始通过print self.pool
查看池位置之前。完成此操作后,我相信当守护进程启动和停止时,池是不一样的。以下是一些输出:
me@pc:~/pyCode/jobQueue$ sudo ./jobQueue.py start
<multiprocessing.pool.Pool object at 0x1c543d0>
me@pc:~/pyCode/jobQueue$ sudo ./jobQueue.py stop
<multiprocessing.pool.Pool object at 0x1fb7450>
closing pool
joining pool
set pool to None
kill process
kill process
... [ stuck in infinite loop]
这些物体的不同位置向我表明,它们不是同一个水池,其中一个可能是僵尸?
在CTRL+C
之后,以下是我从ps aux|grep jobQueue
得到的内容:
root 21161 0.0 0.0 50384 5220 ? Ss 22:59 0:00 /usr/bin/python ./jobQueue.py start
root 21162 0.0 0.0 0 0 ? Z 22:59 0:00 [jobQueue.py] <defunct>
me 21320 0.0 0.0 7624 940 pts/0 S+ 23:00 0:00 grep --color=auto jobQueue
我试过将self.pool = Pool(processes=4)
移动到许多不同的地方。如果它被移动到start()' or
守护进程()中,methods,
打印自身。pool将抛出一个异常,表明它是NoneType。此外,该位置似乎改变了将弹出的僵尸进程的数量。
目前,我还没有添加通过worker运行任何内容的功能。我的问题似乎完全与正确设置工人库有关。我希望您能提供任何有助于解决此问题的信息,或提供有关创建守护进程服务的建议,该服务使用一个工人池来使用Popen
执行一系列命令。由于我还没有走那么远,我不知道未来会面临什么挑战。我想我可能只需要写我自己的游泳池,但如果有一个很好的技巧让游泳池在这里发挥作用,那就太棒了。
解决方案是将self.pool = Pool(process=4)
作为daemonize
方法的最后一行。否则,池最终会在某个地方丢失(可能在fork
s中)。然后可以在run
方法内访问池,该方法由您希望守护的应用程序重载。但是,不能在stop方法中访问池,这样做会导致NoneType异常。我相信有一个更优雅的解决方案,但这是有效的,这是我目前的全部。如果我希望stop
在池仍在运行时失败,我将不得不为run
添加额外的功能和某种形式的消息,但我目前并不关心这一点。