所以我的项目结构如下。我有一个cherrypy服务器和一个执行某些操作的后端服务器。现在我有一个'main'app.py文件来处理启动这些进程。它们的开头就像:
SERVER = subprocess.Popen([PYTHON_EXE_PATH, '-m', WEB_SERVER,
'tvb'], shell=False)
BACKEND = subprocess.Popen([PYTHON_EXE_PATH, '-m', 'bin.rpserver'
, cfg.RPC_SERVER_IP, cfg.RPC_SERVER_PORT],
shell=False)
现在启动它们后,这些pid存储在一个文件中,因此用户可以运行一个停止脚本并关闭它们。这些脚本也可以正常工作,基本上是:
def execute_stop():
if os.path.exists(PID_FILE):
pid_file = open(PID_FILE, 'r')
has_processes = False
for pid in pid_file.read().split('\n'):
if len(pid.strip()):
try:
if sys.platform == 'win32':
import ctypes
handle = ctypes.windll.kernel32.OpenProcess(1, False,
int(pid))
ctypes.windll.kernel32.TerminateProcess(handle, -1)
ctypes.windll.kernel32.CloseHandle(handle)
else:
os.kill(int(pid), signal.SIGKILL)
except Exception, _:
has_processes = True
if has_processes:
sys.stdout.write("Some old PIDs were still registered; \
They could not be stopped.")
pid_file.close()
pid_file = open(PID_FILE, "w")
pid_file.close()
现在这个pid文件,以及我的记录器文件和创建的其他数据文件都保存在cfg.STORAGE
中,我也有一个简单的清理程序:
def execute_clean():
"""Remove TVB folder, TVB File DB, and log file."""
try:
if os.path.isdir(cfg.TVB_STORAGE):
shutil.rmtree(cfg.TVB_STORAGE)
except Exception, excep1:
sys.stdout.write("Could not remove storage folder!")
sys.stdout.write(str(excep1))
单独调用时也可以正常工作。但问题是:我的程序中有一个选项允许用户更改某些设置,在这种情况下整个程序需要重新启动并且应该重做这些步骤。为此我:
cherrypy.engine.exit()
self.logger.debug("Waiting for Cherrypy to terminate.")
sleep(2)
python_path = cfg().get_python_path()
proc_params = [python_path, '-m', 'bin.app', 'start', 'web', 'backend']
subprocess.Popen(proc_params, shell=False)
所以这将基本上再做以下步骤:
execute_stop()
execute_clean()
start both processes again
奇怪的是,我无法理解的是execute_stop()
工作正常,正如您在最后看到的那样PID_FILE
在写入模式下打开并关闭以清除内容,但在execute_clean()
未能说PID_FILE
被另一个进程锁定后,我就立即了。
现在我已经检查并重新检查了,每次打开文件时它都会关闭,我真的不知道该找什么了。这只发生在Windows上,我尝试使用依赖walker来查看发生了什么,似乎当python进程正在运行时,依赖者walker会看到4个引用和2个处理程序到这些文件,这很奇怪,考虑到它们每次都关闭。我也觉得很奇怪,我可以在'w'
模式下打开文件,但我无法删除它们。
任何可能错误/想要寻找的想法都会非常感激。
修改
我尝试过使用#{1}},但在做的时候:
os.waitpid
我得到了 os.waitpid(int(pid), 0)
。我也读过并看到有人说在Windows上你应该将句柄而不是pid传递给os.waitpid所以我也用手柄尝试了但是我得到了相同的结果。那么那个过程应该不再存在了吗?
答案 0 :(得分:0)
这只是在黑暗中拍摄的......
我的预感是SERVER,BACKEND进程中的一个或两个没有按预期终止并且具有打开的PID_FILE。检查它们是否各自用mode='a'
打开PID_FILE并立即关闭它。除非我以SERVER / BACKEND处理PID_FILE的方式偏离基础,否则在致电os.waitpid(pid)
后您也可以尝试TerminateProcess
。这应该阻止,直到该过程真正终止。