Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python subprocess.call()和subprocess.Popen()之间有什么区别使得前者的管道不那么安全?_Python_Python 2.7_Subprocess_Popen_Python 2.6 - Fatal编程技术网

Python subprocess.call()和subprocess.Popen()之间有什么区别使得前者的管道不那么安全?

Python subprocess.call()和subprocess.Popen()之间有什么区别使得前者的管道不那么安全?,python,python-2.7,subprocess,popen,python-2.6,Python,Python 2.7,Subprocess,Popen,Python 2.6,我已经看了他们两个的文档 这个问题是由J.F.在这里的评论引发的: 当前的Python文档说明了如何将管道用于子流程.call(): 注意不要将stdout=PIPE或stderr=PIPE与此功能一起使用。如果子进程生成足够多的输出到管道,以填充操作系统管道缓冲区,则子进程将阻塞,因为没有从中读取管道 Python 2.7: 注意:不要将stdout=PIPE或stderr=PIPE与此函数一起使用,因为这可能会基于子进程输出卷死锁。需要管道时,请将Popen与communicate()方法一

我已经看了他们两个的文档

这个问题是由J.F.在这里的评论引发的:

当前的Python文档说明了如何将
管道
用于
子流程.call()

注意不要将
stdout=PIPE
stderr=PIPE
与此功能一起使用。如果子进程生成足够多的输出到管道,以填充操作系统管道缓冲区,则子进程将阻塞,因为没有从中读取管道

Python 2.7:

注意:不要将
stdout=PIPE
stderr=PIPE
与此函数一起使用,因为这可能会基于子进程输出卷死锁。需要管道时,请将Popen与communicate()方法一起使用

Python2.6不包含此类警告

此外,除了将stdout=PIPE与communicate()一起使用外,用户似乎没有访问其输出的方法:

请注意,如果要将数据发送到进程的
stdin
,则需要使用
stdin=PIPE
创建
Popen
对象。类似地,要在结果元组中获得除None之外的任何内容,还需要给出
stdout=PIPE
和/或
stderr=PIPE

subprocess.call()
subprocess.Popen()
之间有什么区别使得
subprocess.call()的管道
不那么安全


更具体:为什么
subprocess.call()
是“基于子进程输出卷的死锁”,而不是
Popen()

call
Popen
都提供了访问命令输出的方法:

  • 使用
    Popen
    可以使用
    communicate
    或为
    stdout=…
    参数提供文件描述符或文件对象
  • 使用
    call
    时,您唯一的选择是将文件描述符或文件对象传递给
    stdout=…
    参数(您不能使用
    与此参数进行通信)
现在,当与
call
一起使用时,
stdout=PIPE
不安全的原因是
call
在子进程完成之前不会返回,这意味着所有的输出都必须驻留在内存中,如果输出量太多,那么就会填满操作系统管道的缓冲区

您可以验证上述信息的参考资料如下:

  • 根据
    call
    Popen
    的参数相同:
  • 上面所示的论点仅仅是最常见的论点 在下面的常用参数中(因此在 缩写签名)。完整函数签名与 Popen构造函数的函数-此函数传递所有提供的 参数直接传递到该接口

  • 根据
    stdout
    参数的可能值:
  • 有效值是管道,一个现有的文件描述符(正数) 整数)、现有文件对象和无。管道表示一个新的 应创建到子级的管道

    您不应该将
    stdout=PIPE
    call()
    一起使用,因为它不从管道中读取,因此子进程在填充相应的OS管道缓冲区后将立即挂起。下面的图片显示了数据如何在
    command1 | command2
    shell管道中流动:

    不管您的Python版本是什么——管道缓冲区(请看图片)在Python进程之外。Python3不使用C stdio,但它只影响内部缓冲。刷新内部缓冲区时,数据进入管道。如果
    command2
    (您的父Python程序)没有从管道中读取数据,那么
    command1
    (子进程,例如,由
    call()
    )启动的进程将在管道缓冲区满时挂起(在我的Linux机器上为~65K(最大值为
    /proc/sys/fs/pipe max size
    ~1M))


    如果以后使用管道读取,例如使用
    Popen.communicate()
    方法,则可以使用
    stdout=PIPE
    。你也可以。

    //,接下来的问题:Python 2和Python 3之间的这种差异是如何变化的?为什么你总是从
    /
    开始呢?@chepner:嗯,按钮上说的是“添加注释”…:)/,Meta的后续问题:为什么这么少的人有幽默感?”也许,我是,但Python注释符号是“代码”,< < /代码>,不像C++、PHP和JavaScript。/看起来,“管”隐喻很好用。我不知道我能这么直截了当地认为可能有一个塞满了的管子。我想知道为什么内核的管道缓冲区不能自动刷新自己,或者为什么
    call()
    不能刷新缓冲区。为了延伸“管道”的比喻,如果管道安装在可能无法从管道中取出的地方,为什么不留下一个压力激活连接(电磁阀?)到排水槽?(“刷新缓冲区!使代码更难!”-可能的口号?/),我可以猜到为什么一些系统程序员称为“水管工”。这一切都在管道中。有一种说法是“自动刷新管道缓冲区”;它被称为:“drop data”,实现为
    stdout=DEVNULL
    (您可以通过
    call()
    )安全地使用它。)/,啊,但是以后,人们就不能再选择使用
    communicate()
    call()
    的输出或
    check\u call()
    的输出,对吗?@Nathanbassanese:
    call()
    返回子级的退出状态——它是一个普通整数(POSIX上为8位,Windows上为32位);您不能用它调用
    communicate()
    。无论如何,子进程已经死了,甚至它的PID可能已经被其他进程重用