subprocess.call()和subprocess.Popen()之间的区别是什么使PIPE对前者不太安全?

时间:2015-09-02 23:40:33

标签: python python-2.7 subprocess popen python-2.6

我已经查看了这两个文档。

这个问题是由J.F.的评论提示的:Retrieving the output of subprocess.call()

subprocess.call()的当前Python文档说明了如何将PIPE用于subprocess.call()

  

注意请勿对此功能使用stdout=PIPEstderr=PIPE。子进程将阻塞它是否为管道生成足够的输出以填充OS管道缓冲区,因为没有读取管道。

Python 2.7 subprocess.call()

  

注意请勿对此函数使用stdout=PIPEstderr=PIPE,因为这可能会因子进程输出量而死锁。需要管道时,请使用Popen和communic()方法。

Python 2.6不包含此类警告。

此外,subprocess.call() and subprocess.check_call()似乎无法访问其输出,除了使用带有communication()的stdout = PIPE:

https://docs.python.org/2.6/library/subprocess.html#convenience-functions

  

请注意,如果您要将数据发送到流程的stdin,则需要使用Popen创建stdin=PIPE对象。同样,要在结果元组中获取除None之外的任何内容,您还需要提供stdout=PIPE和/或stderr=PIPE

https://docs.python.org/2.6/library/subprocess.html#subprocess.Popen.communicate

subprocess.call()subprocess.Popen()之间的差异使PIPE的{​​{1}}安全性降低了吗?

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

2 个答案:

答案 0 :(得分:18)

call() is just Popen().wait() (± error handling)

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

pipe/stdio buffers

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

如果您稍后从管道中读取,则可以使用Popen.communicate(),例如,使用public static <N,E> void doGenericStatic2(N number, E element) { System.out.println(number); System.out.println(element); } 方法。你也可以pipe_size = fcntl(p.stdout, F_GETPIPE_SZ)

答案 1 :(得分:2)

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

  • 使用Popen,您可以使用communicate或向stdout=...参数提供文件描述符或文件对象。
  • 使用call,您唯一的选择是将文件描述符或文件对象传递给stdout=...参数(您不能将communicate用于此参数)。

现在,stdout=PIPEcall一起使用时不安全的原因是因为call在子流程完成之前不会返回,这意味着所有输出都必须在那个时刻驻留在内存中,如果输出量太多,那么就会填满操作系统管道。缓冲液中。

您可以验证以上信息的参考文献如下:

  1. 根据thiscallPopen的参数相同:
  2.   

    上面显示的参数仅仅是最常见的参数   在下面的常用参数中(因此在...中略微奇怪的表示法)   缩写签名)。完整的功能签名与   Popen构造函数的函数 - 这个函数传递了所有提供的函数   参数直接通过该接口。

    1. 根据thisstdout参数的可能值为:
    2.   

      有效值是PIPE,一个现有的文件描述符(一个正面的   整数),现有文件对象,无。 PIPE表示新的   应该创建给孩子的管道