Python进程在使用tee方案时挂起直到子进程终止

1 投票
2 回答
2385 浏览
提问于 2025-04-16 16:11

我遇到了一个关于进程同步的问题。

我有一个叫做 startup.py 的 Python 脚本,还有一个可执行文件 maestro 和一个可执行文件 tee。我的 Python 脚本 startup.py 启动 maestro 程序,并使用 tee 将 maestro 的错误输出和标准输出同时写入日志文件和控制台。

我用以下代码实现了这个功能:

cmd = "maestro"
mae_err_log = "output.txt"
maestro = subprocess.Popen(cmd, stderr = subprocess.STDOUT, stdout=subprocess.PIPE)
tee = subprocess.Popen(['tee', mae_err_log], stdin = maestro.stdout)
maestro.stdout.close()
tee.communicate()
maestro_status = maestro.returncode
sys.exit(maestro_status)

我的 maestro 程序是一个图形界面程序,当我退出 maestro 程序时,它会内部调用 posix system("maestro_cleanup &") 这个 API,然后立刻退出。我注意到,虽然我在后台运行 maestro_cleanup,但 maestro 程序在 maestro_cleanup 完成之前不会释放控制台。我需要在后台运行 maestro_cleanup,因为它需要一些时间,而我不想在 maestro_cleanup 完成之前占用控制台。使用上面的代码,maestro 程序在 maestro_cleanup 完成之前不会终止。

我看到 "ps -elf" 显示了以下内容:

0 S j 16876  6678  0  75 0 - 65307 wait 18:56 pts/53 00:00:00 python startup.py
0 Z j 17230 16876  4  76 0 - 0     exit 18:56 pts/53 00:00:04 [maestro] <defunct>
0 S j 17231 16876  0  77 0 - 948 pipe_w 18:56 pts/53 00:00:00 /usr/bin/tee output.txt
0 S j 17424     1  0  77   0 -   948 -  18:57 pts/53   00:00:00 maestro_cleanup

你可以看到 maestro_cleanup 的父进程是会话进程 ID,而不是 maestro,因为我是在后台通过系统 API 启动 maestro_cleanup 的。

有没有人知道为什么 maestro 在 maestro_cleanup 完成之前不终止?

任何帮助都非常感谢。

-Vipin

2 个回答

1

我建议你使用 close_fd=True。这样应该就能解决问题了。

1

根据subprocess.Popen 的文档,tee.communicate()确实会“等待进程结束”。而且你调用的方式和那位朋友是一样的,他提到他的子进程是在后台运行的,所以这看起来没问题。因此,这种在退出前阻塞的情况似乎是subprocess的一个限制。

可以试试'Python生成子进程,分离并退出'中的链接,里面提到了ActiveState的一个例子:‘用Python的方式创建一个守护进程’:这是将一个进程从控制终端分离并在后台作为守护进程运行的Python方法。

撰写回答