Python子进程读取进程在编写进程示例之前终止,需要澄清

2024-03-29 10:08:27 发布

您现在位置:Python中文网/ 问答频道 /正文

源代码段:http://docs.python.org/3/library/subprocess.html#replacing-shell-pipeline

output=`dmesg | grep hda`
# becomes
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]

问题:我不太明白为什么需要这一行:p1.stdout.close()? 如果p1 stdout在输出完数据之前就关闭了,而p2还活着呢?我们这么快就关闭p1.stdout不是冒着这个风险吗?这是怎么回事?你知道吗


Tags: orghttpdocscloseoutput源代码stdoutlibrary
2条回答

p1.stdout.close()关闭Python对文件描述符的拷贝。p2已经打开了该描述符(通过stdin=p1.stdout),因此关闭Python的描述符不会影响p2。但是,现在管道末端只打开了一次,所以当它关闭时(例如,如果p2死亡,p1将看到管道关闭,并将得到SIGPIPE。你知道吗

如果在Python中没有关闭p1.stdout,并且p2死亡,p1将不会得到信号,因为Python的描述符将保持管道打开。你知道吗

管道位于进程的外部(它是一个操作系统的东西),由进程使用读写句柄进行访问。许多进程可能有管道句柄,如果管理不当,可能以各种灾难性的方式进行读写。当管道的所有手柄关闭时,管道关闭。你知道吗

虽然进程执行在Linux和Windows中的工作方式不同,但基本上是这样的(我要为此付出代价!)你知道吗

p1 = Popen(["dmesg"], stdout=PIPE)

创建管道1,给dmesg一个写句柄作为其stdout,并在父级中返回一个读句柄作为p1.stdout。现在您有了一个带有2个句柄的管道(pipe\u 1 write in dmesg,pipe\u 1 read in parent)。你知道吗

p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)

创建管道2。给grep一个管道2的写句柄和管道1的读句柄的副本。现在您有了2个管道和5个句柄(在dmesg中写入管道1、在grep中读取管道1和写入管道2、在父级中读取管道1和读取管道2)。你知道吗

p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.

请注意,管道1有两个读取句柄。您希望grep具有读取句柄,以便它读取dmesg数据。您不再需要父级中的句柄。关闭它,使管道1上只有一个读取句柄。如果grep死了,它的pipe_1读取句柄将关闭,操作系统会注意到pipe_1没有剩余的读取句柄,并向dmesg发出坏消息。你知道吗

output = p2.communicate()[0]

dmesg将数据发送到stdout(pipe1写入句柄),stdout开始填充pipe1。grep读取stdin(管道读取句柄),它清空管道。grep还编写stdout(pipe2写入句柄)来填充pipe2。父进程读取管道2。。。你给自己弄了条管道!你知道吗

相关问题 更多 >