gpt4 book ai didi

Python 子进程 Popen.communicate() 等价于 Popen.stdout.read()?

转载 作者:IT老高 更新时间:2023-10-28 22:08:32 26 4
gpt4 key购买 nike

非常具体的问题(我希望):以下三个代码有什么区别?

(我希望它只是第一个不等待子进程完成,而第二个和第三个会这样做。但我需要确定这是 only 的区别...)

我也欢迎其他评论/建议(尽管我已经很清楚 shell=True 的危险和跨平台限制)

请注意,我已经阅读了 Python subprocess interaction, why does my process work with Popen.communicate, but not Popen.stdout.read()?并且我不想/不需要之后与程序交互。

另外请注意,我已经阅读了 Alternatives to Python Popen.communicate() memory limitations?但我并没有真正明白...

最后,请注意,我知道当一个缓冲区使用一种方法填充一个输出时,某处存在死锁的风险,但我在互联网上寻找明确的解释时迷路了......

第一个代码:

from subprocess import Popen, PIPE

def exe_f(command='ls -l', shell=True):
"""Function to execute a command and return stuff"""

process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

stdout = process.stdout.read()
stderr = process.stderr.read()

return process, stderr, stdout

第二个代码:

from subprocess import Popen, PIPE
from subprocess import communicate

def exe_f(command='ls -l', shell=True):
"""Function to execute a command and return stuff"""

process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

(stdout, stderr) = process.communicate()

return process, stderr, stdout

第三个代码:

from subprocess import Popen, PIPE
from subprocess import wait

def exe_f(command='ls -l', shell=True):
"""Function to execute a command and return stuff"""

process = Popen(command, shell=shell, stdout=PIPE, stderr=PIPE)

code = process.wait()
stdout = process.stdout.read()
stderr = process.stderr.read()

return process, stderr, stdout

谢谢。

最佳答案

如果您查看 subprocess.communicate() 的源代码,它显示了一个完美的差异示例:

def communicate(self, input=None):
...
# Optimization: If we are only using one pipe, or no pipe at
# all, using select() or threads is unnecessary.
if [self.stdin, self.stdout, self.stderr].count(None) >= 2:
stdout = None
stderr = None
if self.stdin:
if input:
self.stdin.write(input)
self.stdin.close()
elif self.stdout:
stdout = self.stdout.read()
self.stdout.close()
elif self.stderr:
stderr = self.stderr.read()
self.stderr.close()
self.wait()
return (stdout, stderr)

return self._communicate(input)

您可以看到 communicate 确实使用了对 stdoutstderr 的读取调用,并且还调用了 wait() 。这只是操作顺序的问题。在您的情况下,因为您对 stdout 和 stderr 都使用 PIPE,所以它进入 _communicate():

def _communicate(self, input):
stdout = None # Return
stderr = None # Return

if self.stdout:
stdout = []
stdout_thread = threading.Thread(target=self._readerthread,
args=(self.stdout, stdout))
stdout_thread.setDaemon(True)
stdout_thread.start()
if self.stderr:
stderr = []
stderr_thread = threading.Thread(target=self._readerthread,
args=(self.stderr, stderr))
stderr_thread.setDaemon(True)
stderr_thread.start()

if self.stdin:
if input is not None:
self.stdin.write(input)
self.stdin.close()

if self.stdout:
stdout_thread.join()
if self.stderr:
stderr_thread.join()

# All data exchanged. Translate lists into strings.
if stdout is not None:
stdout = stdout[0]
if stderr is not None:
stderr = stderr[0]

# Translate newlines, if requested. We cannot let the file
# object do the translation: It is based on stdio, which is
# impossible to combine with select (unless forcing no
# buffering).
if self.universal_newlines and hasattr(file, 'newlines'):
if stdout:
stdout = self._translate_newlines(stdout)
if stderr:
stderr = self._translate_newlines(stderr)

self.wait()
return (stdout, stderr)

这使用线程一次从多个流中读取。然后它在最后调用 wait()

总结一下:

  1. 此示例一次从一个流中读取,并且不等待它完成该过程。
  2. 此示例通过内部线程同时从两个流中读取,并等待它完成该过程。
  3. 此示例等待进程完成,然后一次读取一个流。正如您所提到的,如果流中写入的内容过多,则可能会出现死锁。

另外,您在第二个和第三个示例中不需要这两个 import 语句:

from subprocess import communicate
from subprocess import wait

它们都是 Popen 对象的方法。

关于Python 子进程 Popen.communicate() 等价于 Popen.stdout.read()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12965023/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com