python subprocess - 分离一个进程
python subprocess - detach a process
我有一个 python 脚本 af_audit_run.py
,它通过 subprocess
.
调用另一个 python 脚本 request_audit.py
第二个脚本 request_audit.py
在后台调用另一个子进程和 returns 一个请求 ID。
问题是第一个脚本 af_audit_run.py
应该在第二个脚本 returns 请求 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
-- 不等待,只分离一个子进程(第 3 个 python 脚本)和 returns 请求 ID:
subprocess.Popen(cmd, shell=True, stdout=None, stderr=None, close_fds=True)
print(request_id)
环境:Linux
您需要确保第三个进程的标准输出和标准错误指向某个地方,而不是 af_audit_run.py
从中读取输出的管道。
现有代码的问题在于,通过使用 stdout=None, stderr=None
,您正在请求 default 操作(就好像您根本没有使用这些关键字一样).这是写入与 parent 进程相同的输出流,在本例中为 request_audit.py
,使用子进程分叉时继承的文件描述符。这意味着 top-level af_audit_run.py
将等待输出,因为在第三个进程完成之前它不会在该输出流上看到 end-of-file。
这可以在 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
这是 lsof
输出的一部分 top-level 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
如您所见,此示例中的 sleep
进程 (pid 3057) 将其 stdout (fd 1) 和 stderr (fd 2) 流连接到 top-level process (pid 3053) is reading from -- 注意 second-last 列中的管道号 -- 即使它不是直接的 parent 该进程。
您指定的是 close_fds=True
,但这是 documented,如下所示:
"如果 close_fds 为真,所有文件描述符 除了 0、1 和 2 将在 child 进程被执行。" (强调我的)
因此它对 stdin、stdout 或 stderr 流没有任何影响,尽管任何 other 打开的文件描述符将在 child.
如果您使用 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
,这样如果进程尝试读取,它就会看到 end-of-file。在这个例子中我没有这样做,它的输入仍然连接到终端设备,虽然这不影响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)
我有一个 python 脚本 af_audit_run.py
,它通过 subprocess
.
request_audit.py
第二个脚本 request_audit.py
在后台调用另一个子进程和 returns 一个请求 ID。
问题是第一个脚本 af_audit_run.py
应该在第二个脚本 returns 请求 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
-- 不等待,只分离一个子进程(第 3 个 python 脚本)和 returns 请求 ID:
subprocess.Popen(cmd, shell=True, stdout=None, stderr=None, close_fds=True)
print(request_id)
环境:Linux
您需要确保第三个进程的标准输出和标准错误指向某个地方,而不是 af_audit_run.py
从中读取输出的管道。
现有代码的问题在于,通过使用 stdout=None, stderr=None
,您正在请求 default 操作(就好像您根本没有使用这些关键字一样).这是写入与 parent 进程相同的输出流,在本例中为 request_audit.py
,使用子进程分叉时继承的文件描述符。这意味着 top-level af_audit_run.py
将等待输出,因为在第三个进程完成之前它不会在该输出流上看到 end-of-file。
这可以在 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
这是 lsof
输出的一部分 top-level 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
如您所见,此示例中的 sleep
进程 (pid 3057) 将其 stdout (fd 1) 和 stderr (fd 2) 流连接到 top-level process (pid 3053) is reading from -- 注意 second-last 列中的管道号 -- 即使它不是直接的 parent 该进程。
您指定的是 close_fds=True
,但这是 documented,如下所示:
"如果 close_fds 为真,所有文件描述符 除了 0、1 和 2 将在 child 进程被执行。" (强调我的)
因此它对 stdin、stdout 或 stderr 流没有任何影响,尽管任何 other 打开的文件描述符将在 child.
如果您使用 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
,这样如果进程尝试读取,它就会看到 end-of-file。在这个例子中我没有这样做,它的输入仍然连接到终端设备,虽然这不影响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)