为什么python的subprocess.call是这样实现的?

Lau*_*low 13 python subprocess

子进程模块具有便捷功能call,在2.6和3.1中都是这样实现的:

def call(*popenargs, **kwargs):
    return Popen(*popenargs, **kwargs).wait()
Run Code Online (Sandbox Code Playgroud)

该功能的文档带有红色警告,阅读:

警告:比如Popen.wait(),当使用stdout=PIPE和/或stderr=PIPE子进程生成足够的输出到管道时它会死锁,这样它就会阻塞等待OS管道缓冲区接受更多数据.

Popen.wait()文件说,使用Popen.communicate(),而不是在这种情况下.那么,为什么不call只是像下面那样实现,所以可以删除愚蠢的警告,并从标准库中删除这样的愚蠢限制?

def call(*args, **kwargs):
    input = kwargs.pop("input", None)
    p = Popen(*args, **kwargs)
    p.communicate(input)
    return p.returncode
Run Code Online (Sandbox Code Playgroud)

我确定这是有原因的.我错过了什么?

Jos*_*ley 8

我花了一些时间浏览PEP-324,它介绍了子过程模块,试图找出所涉及的设计决策,但我认为答案实际上非常简单:

没有理由来传递stdout=PIPEstderr=PIPEsubprocess.call,这样一个事实,即它可以死锁是无关紧要的.

唯一的原因,传递stdout=PIPEstderr=PIPEsubprocess.Popen是让你可以使用POPEN实例的stdout,并stderr为文件对象的属性.由于subprocess.call永远不会让您看到Popen实例,因此PIPE选项变得无关紧要.

Popen.communicate(通过监视管道来创建额外的线程以避免死锁)可能存在开销,并且在这种情况下没有任何好处,因此没有理由使用它.

编辑:如果你想丢弃你的输出,我想最好这样做明确:

# option 1
with open(os.devnull, 'w') as dev_null:
    subprocess.call(['command'], stdout=dev_null, stderr=dev_null)

# option 2
subprocess.call(['command >& /dev/null'], shell=True)
Run Code Online (Sandbox Code Playgroud)

而不是指示子进程将所有输出捕获到您从未打算使用的PIPE文件.