gpt4 book ai didi

python - 无法在python3中获取子进程返回码

转载 作者:行者123 更新时间:2023-11-28 16:19:56 25 4
gpt4 key购买 nike

我正在尝试为我的 python 守护进程制作类似 supervisor 的东西,发现相同的代码在 python2 中有效,但在 python3 中无效。

一般来说,我会使用这个最小的示例代码。

daemon.py

#!/usr/bin/env python

import signal
import sys
import os


def stop(*args, **kwargs):
print('daemon exited', os.getpid())
sys.exit(0)


signal.signal(signal.SIGTERM, stop)

print('daemon started', os.getpid())

while True:
pass

supervisor.py

import os
import signal
import subprocess

from time import sleep


parent_pid = os.getpid()
commands = [
[
'./daemon.py'
]
]
popen_list = []
for command in commands:
popen = subprocess.Popen(command, preexec_fn=os.setsid)
popen_list.append(popen)


def stop_workers(*args, **kwargs):
for popen in popen_list:
print('send_signal', popen.pid)
popen.send_signal(signal.SIGTERM)

while True:
popen_return_code = popen.poll()
if popen_return_code is not None:
break
sleep(5)


signal.signal(signal.SIGTERM, stop_workers)

for popen in popen_list:
print('wait_main', popen.wait())

如果你运行 supervisor.py 然后在它的 pid 上调用 kill -15,那么它会卡在无限循环中,因为 popen_return_code 永远不会不是 None。我发现,这主要是因为为 wait_pid 操作添加了 threading.Lock ( source ),但我如何重写代码才能正确处理子退出?

最佳答案

这是一个有趣的案例。

我花了几个小时试图找出发生这种情况的原因,此刻我唯一想到的是 wait()poll( )python3python2.7 中发生了变化。

查看 python3/suprocess.py 实现的源代码,我们可以看到当您调用 wait() 方法时会发生锁获取>Popen 对象,见

https://github.com/python/cpython/blob/master/Lib/subprocess.py#L1402 .

此锁阻止进一步的 poll() 调用按预期工作,直到 wait() 获取的锁被释放,参见

https://github.com/python/cpython/blob/master/Lib/subprocess.py#L1355

并在那里发表评论

Something else is busy calling waitpid. Don't allow two at once. We know nothing yet.

python2.7/subprocess.py 中没有这样的锁,所以这看起来像是它在 python2.7 中工作而在python3.

但是我没有看到你为什么要在信号处理程序中尝试 poll() 的原因,请尝试如下重写你的 supervisor.py,这应该可以工作在 python3python2.7

上都符合预期

supervisor.py

import os
import signal
import subprocess

from time import sleep


parent_pid = os.getpid()
commands = [
[
'./daemon.py'
]
]
popen_list = []
for command in commands:
popen = subprocess.Popen(command, preexec_fn=os.setsid)
popen_list.append(popen)


def stop_workers(*args, **kwargs):
for popen in popen_list:
print('send_signal', popen.pid)
popen.send_signal(signal.SIGTERM)

signal.signal(signal.SIGTERM, stop_workers)

for popen in popen_list:
print('wait_main', popen.wait())

希望对你有帮助

关于python - 无法在python3中获取子进程返回码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41135620/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com