【问题标题】:python subprocess - detach a processpython subprocess - 分离一个进程
【发布时间】:2020-10-12 17:47:44
【问题描述】:

我有一个python脚本af_audit_run.py,它通过subprocess调用另一个python脚本request_audit.py

第二个脚本request_audit.py在后台调用另一个子进程并返回一个请求ID。

问题是第一个脚本af_audit_run.py,应该在第二个脚本返回请求ID后很快退出,正在等待整个后台进程完成。有什么方法可以强制第一个脚本在请求 id 返回后立即退出?

af_audit_run.py -- 使用communicate 方法等待结果:

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 
stderr=subprocess.PIPE)
result, error = p.communicate()
print(result.decode('utf-8'))
print(error.decode('utf-8'))

request_audit.py -- 不等待,只是分离一个子进程(第三个 python 脚本)并返回请求 ID:

subprocess.Popen(cmd, shell=True, stdout=None, stderr=None, close_fds=True)
print(request_id)

环境:Linux

【问题讨论】:

  • 请您显示现有代码的相关部分。
  • @alaniwi,我已经更新了代码 sn-p。
  • 如果你使用stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL而不是stdout=None, stderr=None,它就可以工作。 (我会在答案中提供更多细节。)
  • @alaniwi,这将重定向输出,但无助于第一个脚本在获取返回码后立即出现。我希望第一个脚本不要等待第二个脚本后台进程完成。
  • 你试过了吗?

标签: python subprocess


【解决方案1】:

您需要确保第三个进程的标准输出和标准错误被定向到除af_audit_run.py 正在读取输出的管道之外的其他地方。

现有代码的问题在于,通过使用stdout=None, stderr=None,您正在请求 default 操作(就好像您根本没有使用这些关键字一样)。这是写入与父进程相同的输出流,在本例中为request_audit.py,使用子进程分叉时继承的文件描述符。这意味着顶级af_audit_run.py 将等待输出,因为在第三个进程完成之前它不会看到该输出流上的文件结尾。

这可以在lsof 的输出中看到——在下面的例子中,第三个进程是命令/bin/sleep 600(见最后的测试代码)。

这是第三个进程的lsof 输出的一部分:

sleep   3057  myuser    0u   CHR 136,20      0t0      23 /dev/pts/20
sleep   3057  myuser    1w  FIFO   0,13      0t0 9441062 pipe
sleep   3057  myuser    2w  FIFO   0,13      0t0 9441063 pipe

这是顶级af_audit_run.pylsof 输出的一部分:

python3 3053  myuser    0u   CHR 136,20      0t0      23 /dev/pts/20
python3 3053  myuser    1u   CHR 136,20      0t0      23 /dev/pts/20
python3 3053  myuser    2u   CHR 136,20      0t0      23 /dev/pts/20
python3 3053  myuser    3r  FIFO   0,13      0t0 9441062 pipe
python3 3053  myuser    5r  FIFO   0,13      0t0 9441063 pipe

如您所见,此示例中的sleep 进程(pid 3057)将其 stdout(fd 1)和 stderr(fd 2)流连接到顶层进程(pid 3053)的写入端) 正在读取——注意倒数第二列中的管道编号——即使它不是该进程的直接父进程。

您指定的是close_fds=True,但这是documented,如下所示:

“如果 close_fds 为真,则所有文件描述符除了 0、1 和 2 将在子进程执行之前关闭。” (强调我的)

因此它对标准输入、标准输出或标准错误流没有任何影响,尽管任何其他打开的文件描述符都会在子进程中关闭。

如果您使用stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL 而不是stdout=None, stderr=None,那么这会将这些流显式定向到空设备(Linux 上的/dev/null),然后af_audit_run.py 不必等待它。

lsof 在这种情况下的一些输出:

sleep   3318  myuser    0u   CHR 136,20      0t0      23 /dev/pts/20
sleep   3318  myuser    1u   CHR    1,3      0t0       6 /dev/null
sleep   3318  myuser    2u   CHR    1,3      0t0       6 /dev/null

也可以使用stdin=subprocess.DEVNULL,这样如果进程试图读取,它就会看到文件结束。在这个例子中我没有这样做,它的输入仍然连接到终端设备,虽然这并不影响af_audit_run.py是否等待它。


测试代码

af_audit_run.py

import subprocess

cmd = "python3 request_audit.py"

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 
                     stderr=subprocess.PIPE)
result, error = p.communicate()
print(result.decode('utf-8'))
print(error.decode('utf-8'))

request_audit.py

import subprocess

cmd = "/bin/sleep 600"

subprocess.Popen(cmd, shell=True,
                 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

print(5)

【讨论】:

    猜你喜欢
    • 2015-10-07
    • 2015-09-01
    • 2020-04-26
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多