ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

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

2019-11-12 00:56:30  阅读:193  来源: 互联网

标签:python-3-x subprocess python


我试图为我的python守护进程创建类似超级用户的东西,发现相同的代码在python2中有效,而在python3中不起作用.

通常,我来介绍这个最小的示例代码.

守护进程

#!/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())

如果您运行supervisor.py,然后在其pid上调用kill -15,则它将死于无限循环,因为popen_return_code永远不会不是None.我发现,这基本上是因为添加了threading.Lock用于wait_pid操作(source),但是如何重写代码以使其能够正确处理子退出?

解决方法:

这是一个有趣的案例.

我花了几个小时试图弄清楚为什么会发生这种情况,而我现在想到的唯一一件事就是,在python3和python2.7中已经更改了wait()和poll()的实现.

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

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,这应该在python3和python2.7上都能正常工作

主管

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-3-x,subprocess,python
来源: https://codeday.me/bug/20191112/2023521.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有