无法在python3中获取子进程返回代码
我正在尝试为我的python守护进程创建类似supervisor的东西,发现同样的代码在python2中工作,在python3中不工作 一般来说,我已经得到了这个最小的示例代码 守护进程.py无法在python3中获取子进程返回代码,python,python-3.x,subprocess,Python,Python 3.x,Subprocess,我正在尝试为我的python守护进程创建类似supervisor的东西,发现同样的代码在python2中工作,在python3中不工作 一般来说,我已经得到了这个最小的示例代码 守护进程.py #!/usr/bin/env python import signal import sys import os def stop(*args, **kwargs): print('daemon exited', os.getpid()) sys.exit(0) signal.s
#!/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
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())
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())
supervisor.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
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())
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())
如果运行supervisor.py,然后在其pid上调用
kill-15
,那么它将挂起在无限循环中,因为popen\u return\u code永远不会是None。我发现,这基本上是因为添加了threading.Lock for wait_pid operation(),但是我如何重写代码以便正确处理子退出?这是一个有趣的案例
我花了几个小时试图找出发生这种情况的原因,目前我唯一想到的是,wait()
和poll()
的实现在python3
和python2.7
中发生了变化
查看python3/supprocess.py
实现的源代码,我们可以看到在调用Popen
对象的wait()
方法时发生锁获取,请参见
此锁阻止进一步的poll()
调用按预期工作,直到wait()
获取的锁被释放,请参阅
并在那里发表评论
有人正忙着给waitpid打电话。不允许两个
马上。我们什么都不知道
在python2.7/subprocess.py
中没有这样一个锁,因此这似乎是它在python2.7
中工作而在python3
中不工作的原因
但是,我看不出您为什么要在信号处理程序中尝试poll()
,请尝试按如下方式重写您的supervisor.py
,这应该在python3
和python2.7
上都能正常工作
supervisor.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
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())
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())
希望这有帮助一般来说,我同意@risboo6909的答案,但也有一些想法,如何解决这种情况
subaccess.Popen
更改为psutil.Popen
popen.wait()
中,您可以只执行无限循环,因为进程将在信号处理程序中退出如果我不处理child exist并只发送SIGTERM,那么当我的孩子没有实现handler(尝试从
daemon.py
中删除sys.exit
)时,它将被分离到init进程。对于popen\u列表中的popen:print('wait\u main',popen.wait()),很抱歉,这里有混乱的评论:(