2011-06-29 47 views
3

我对这个问题提出了一个问题,并没有得到一个足够透彻的答案来解决这个问题(很可能是由于缺乏严谨的解释我正在尝试纠正的问题):Zombie process in python multiprocessing daemon守护进程中的Python多处理池

我想实现一个python守护进程,它使用工作池来执行命令,使用Popen。我从http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/

借来的基本守护我只是改变了initdaemonize(或等同的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) 

我没有设置标准输入,输出和错误,这样我可以调试与打印报表的代码。另外,我尝试将这个池移动到几个地方,但这是唯一不会产生异常的地方。

这里有更改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查看泳池位置之前。这样做后,我相信守护进程启动时以及停止时,池不一样。下面是一些输出:

[email protected]:~/pyCode/jobQueue$ sudo ./jobQueue.py start 
<multiprocessing.pool.Pool object at 0x1c543d0> 
[email protected]:~/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 daemonize()methods, print self.pool`将会抛出一个异常,说它是NoneType。另外,该位置似乎改变了会弹出的僵尸进程数量。

目前,我还没有添加通过工作人员运行任何东西的功能。我的问题似乎与正确设置工作人员池完全相关。我希望能够解决这个问题的任何信息或者关于创建使用工作人员池来执行一系列使用Popen的一系列命令的守护程序服务的建议。由于我没有那么远,我不知道我面临的挑战是什么。我想我可能只需要编写自己的游泳池,但如果有一个很好的窍门可以让游泳池在这里工作,那将是惊人的。

+0

我想我已经想出了我需要做的事情,但我不知道该怎么做。守护进程内部写入一个pid文件。无论何时调用start或stop,它都会从文件中获取守护进程的PID。我需要对池进程的PID做同样的事情,但是怎么做? –

回答

1

解决的办法是将self.pool = Pool(process=4)作为daemonize方法的最后一行。否则,游泳池最终会在某处丢失(可能在fork s)。然后池可以在run方法内访问,该方法由您希望守护进程的应用程序重载。但是,在停止方法中无法访问池,并且这样做会导致出现NoneType异常。我相信有一个更优雅的解决方案,但这是有效的,这是我现在所拥有的。如果我希望stop在池仍在运行时发生故障,我将不得不为run添加附加功能和某种形式的消息,但我目前不关心这一点。

+0

呃。实际上它非常简单,我只需要将'self.pool = Pool(process = 4)'放在守护进程的'run'方法中,但这仍然不允许我使用'close'' join '很好地清理池的方法。任何其他解决方案将不胜感激。 –