python - 为什么子进程在关闭后仍然可以写入标准输出?

标签 python subprocess pipe

我在 subprocess documentation 中找到了这段代码,其中一个进程的标准输出被管道传输到另一个进程:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

我对 stdout.close() 调用感到困惑。关闭 stdout 句柄肯定会阻止进程产生任何输出吗?

所以我进行了一个实验,令我惊讶的是这个过程根本没有受到它的影响:

from subprocess import Popen, PIPE

p1 = Popen(['python', '-c', 'import time; time.sleep(5); print(1)'], stdout=PIPE)
p2 = Popen(['python', '-c', 'print(input()*3)'], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
print('stdout closed')
print('stdout:', p2.communicate()[0])

# output:
# stdout closed
# [5 second pause]
# stdout: b'111\n'

这是怎么回事?为什么进程可以写入一个关闭的管道?

最佳答案

关闭文件描述符只是意味着减少引用计数(在操作系统内核中)。描述符编号变为无效,但除非引用计数为零,否则它所引用的对象不会发生任何事情。

Popen 调用中,正在执行复制文件描述符的操作,从而增加引用计数:像 dup/dup2 这样的操作和 fork

如果我们fork 一个从父进程接收文件描述符的子进程,则该文件描述符是指向同一个对象的副本。

如果父级关闭该描述符的原始副本,则不会影响子级中的那个。反之亦然。只有父子双方都关闭了那个描述符,底层打开的文件/设备对象才会消失;并且仅当没有其他描述符引用它时。

即使描述符具有相同的编号也是如此;每个进程都有自己的文件描述符编号表。子文件描述符 3 与父文件描述符 3 不同。

关于python - 为什么子进程在关闭后仍然可以写入标准输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49719673/

相关文章:

python - 从 python 执行 DevCon CMD 命令

python - 从python在windows上找到bash可执行文件的位置

python - _subprocess 模块

python-3.x - 为什么 select.select 告诉我它不可读

python - Python 中的评级控制

python - 使用 scipy generic_filter 和 numpy Median_filter 计算移动中位数会给出不同的输出

python - 为什么python openCV不按我期望的方式更改背景颜色?

python - Pandas 如何截断小浮点值

javascript - 为客户端(浏览器)PDF 生成分块和传输大量数据

linux - 忽略 linux 管道中的错误