python subprocess - 分离进程

Rav*_*dra 3 python subprocess

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

第二个脚本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'))
Run Code Online (Sandbox Code Playgroud)

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

subprocess.Popen(cmd, shell=True, stdout=None, stderr=None, close_fds=True)
print(request_id)
Run Code Online (Sandbox Code Playgroud)

环境:Linux

ala*_*ani 5

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

现有代码的问题在于,通过使用stdout=None, stderr=None,您正在请求默认操作(就好像您根本没有使用这些关键字一样)。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
Run Code Online (Sandbox Code Playgroud)

这是lsof顶层输出的一部分af_audit_run.py

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
Run Code Online (Sandbox Code Playgroud)

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

您正在指定close_fds=True,但这记录如下:

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

因此,它对 stdin、stdout 或 stderr 流没有任何影响,尽管任何其他打开的文件描述符将在子级中关闭。

如果您不stdout=None, stderr=None使用stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,那么这将显式地将这些流定向到空设备(/dev/null在 Linux 上),然后就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
Run Code Online (Sandbox Code Playgroud)

也可以使用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'))
Run Code Online (Sandbox Code Playgroud)

request_audit.py

import subprocess

cmd = "/bin/sleep 600"

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

print(5)
Run Code Online (Sandbox Code Playgroud)