Python Popen - wait vs communication vs CalledProcessError

Mr_*_*s_D 6 python error-handling popen python-2.7

继续我之前的问题,我看到要获取我在python中通过Popen生成的进程的错误代码,我必须调用wait()或communic()(可以用来访问Popen stdout和stderr属性):

app7z = '/path/to/7z.exe'
command = [app7z, 'a', dstFile.temp, "-y", "-r", os.path.join(src.Dir, '*')]
process = Popen(command, stdout=PIPE, startupinfo=startupinfo)
out = process.stdout
regCompressMatch = re.compile('Compressing\s+(.+)').match
regErrMatch = re.compile('Error: (.*)').match
errorLine = []
for line in out:
    if len(errorLine) or regErrMatch(line):
        errorLine.append(line)
    if regCompressMatch(line):
        # update a progress bar
result = process.wait() # HERE
if result: # in the hopes that 7z returns 0 for correct execution
    dstFile.temp.remove()
    raise StateError(_("%s: Compression failed:\n%s") % (dstFile.s, 
                       "\n".join(errorLine)))
Run Code Online (Sandbox Code Playgroud)

然而,文档警告wait()可能会死锁(当stdout = PIPE,这是这里的情况)communicate()可能会溢出.所以:

  1. 在这里使用什么是正确的?请注意,我确实使用输出
  2. 我应该如何使用沟通?可不可能是:

    process = Popen(command, stdout=PIPE, startupinfo=startupinfo)
    out = process.communicate()[0]
    # same as before...
    result = process.returncode
    if result: # ...
    
    Run Code Online (Sandbox Code Playgroud)

    不确定阻塞和内存错误

  3. 有没有更好/更pythonic的方式处理问题?我不认为subprocess.CalledProcessErrorsubprocess.check_call/check_output适用于我的情况 - 或者他们呢?

免责声明:我没有编写代码,我是当前的维护者,因此问题3.

有关:

如果这有所不同,我在Windows上 - python 2.7.8

应该有一个 - 最好只有一个 - 明显的方法来做到这一点

jfs*_*jfs 11

  • 有关死锁的:它是安全的使用stdout=PIPEwait()一起当且仅当您从管道中读取..communicate()做阅读并打电话wait()给你
  • 关于内存:如果输出可以无限制,那么你不应该使用.communicate()它累积内存中的所有输出.

在这里使用什么是正确的?

要启动子进程,请逐行读取其输出并等待它退出:

#!/usr/bin/env python
from subprocess import Popen, PIPE

process = Popen(command, stdout=PIPE, bufsize=1)
with process.stdout:
    for line in iter(process.stdout.readline, b''): 
        handle(line)
returncode = process.wait() 
Run Code Online (Sandbox Code Playgroud)

由于有限的OS管道缓冲区,此代码不会死锁.此外,代码支持无限输出的命令(如果单个行适合内存).

iter()用于在刷新子进程'stdout缓冲区后立即读取一行,以解决Python 2中的预读错误.for line in process.stdout如果您在编写行时不需要读取行而不等待缓冲区填充或子进程结束,则可以使用简单的方法.请参阅Python:从subprocess.communicate()读取流输入.

如果您知道命令输出在所有情况下都可以适合内存,那么您可以一次获得输出:

#!/usr/bin/env python
from subprocess import check_output

all_output = check_output(command)
Run Code Online (Sandbox Code Playgroud)

CalledProcessError如果命令以非零退出状态返回,则会引发此异常.内部,check_output()使用Popen().communicate()

应该有一个 - 最好只有一个 - 明显的方法来做到这一点

subprocess.Popen()是在许多情况下工作的主要API.还有便利的功能/方法,例如Popen.communicate(),check_output(),check_call()以便共同使用情况.

有多种方法,功能因为有多个不同的用例.


归档时间:

查看次数:

10036 次

最近记录:

10 年,5 月 前