Python subprocess.Popen communicate() 和wait()使用上的区别

摘要:
出现此问题的原因是,调用Popen的等待方法后发现程序没有返回。谷歌发现,等待时可能会产生死锁。如果stdout或stderr参数是管道,则使用Pope。wait()方法等待程序完成获取返回值。

之所以会纠结到这个问题上是因为发现在调用Popen的wait方法之后程序一直没有返回。google发现wait是有可能产生死锁的。为了把这个问题彻底弄清楚,搜索一些资料过来看看:

原文链接:http://blog.csdn.net/carolzhang8406/article/details/22286913

看到别人的例子:

今天遇到的一个问题。简单说就是,使用 subprocess 模块的 Popen 调用外部程序,如果 stdoutstderr 参数是 pipe,并且程序输出超过操作系统的 pipe size时,如果使用 Popen.wait() 方式等待程序结束获取返回值,会导致死锁,程序卡在 wait() 调用上。

ulimit -a 看到的 pipe size 是 4KB,那只是每页的大小,查询得知 linux 默认的 pipe size 是 64KB

看例子:

#!/usr/bin/env python
# coding: utf-8
# yc@2013/04/28

import subprocess

def test(size):
    print 'start'

    cmd = 'dd if=/dev/urandom bs=1 count=%d 2>/dev/null' % size
    p = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
    #p.communicate()
    p.wait()

    print 'end'

# 64KB
test(64 * 1024)

# 64KB + 1B
test(64 * 1024 + 1)

首先测试输出为 64KB 大小的情况。使用 dd 产生了正好 64KB 的标准输出,由 subprocess.Popen 调用,然后使用 wait() 等待 dd 调用结束。可以看到正确的 startend 输出;然后测试比 64KB 多的情况,这种情况下只输出了 start,也就是说程序执行卡在了 p.wait() 上,程序死锁。具体输出如下:

start
end
start

那死锁问题如何避免呢?官方文档里推荐使用 Popen.communicate()。这个方法会把输出放在内存,而不是管道里,所以这时候上限就和内存大小有关了,一般不会有问题。而且如果要获得程序返回值,可以在调用 Popen.communicate() 之后取 Popen.returncode 的值。

结论:如果使用 subprocess.Popen,就不使用 Popen.wait(),而使用 Popen.communicate() 来等待外部程序执行结束。

Popen.wait()

Wait for child process to terminate.  Set and returnreturncode attribute.

Warning

This will deadlock when using stdout=PIPE and/orstderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data.  Use communicate() to avoid that.

Popen.communicate(input=None)

Interact with process: Send data to stdin.  Read data from stdout and stderr, until end-of-file is reached.  Wait for process to terminate. The optionalinput argument should be a string to be sent to the child process, orNone, if no data should be sent to the child.

communicate() returns a tuple (stdoutdata, stderrdata).

Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE.  Similarly, to get anything other thanNone in the result tuple, you need to give stdout=PIPE and/orstderr=PIPE too.

Note

The data read is buffered in memory, so do not use this method if the data size is large or unlimited.

subprocess 的两种方法:

1)如果想调用之后直接阻塞到子程序调用结束:

Depending on how you want to work your script you have two options. If you want the commands to block and not do anything while it is executing, you can just use subprocess.call.

#start and block until done
subprocess.call([data["om_points"], ">", diz['d']+"/points.xml"])


2)非阻塞的时候方式:

If you want to do things while it is executing or feed things into stdin, you can use communicate after the popen call.

#start and process things, then wait
p = subprocess.Popen(([data["om_points"], ">", diz['d']+"/points.xml"])
print "Happens while running"
p.communicate() #now wait

As stated in the documentation, wait can deadlock, so communicate is advisable.

免责声明:文章转载自《Python subprocess.Popen communicate() 和wait()使用上的区别》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇【CCS仿真】如何将CCS仿真时memory中的数据以Hex、Integer、 Long 、Float、 Addressable Unit类型保存到PCsegv & mini coredump 调研下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【转】常用的python模块及安装方法

  adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheetahcherrypy:一个WEB frameworkctypes:用来调用动态链接库DBUtils:数据库连接池django:一个WEB frameworkdocutils:用来写文档的dpkt:数据包的解包和组包...

C#反射实例应用--------获取程序集信息和通过类名创建类实例

AppDomain.CurrentDomain.GetAssemblies();获取程序集,但是获取的只是已经加载的dll,引用的获取不到。 System.Reflection.Assembly.GetEntryAssembly().GetReferencedAssemblies(); 获取程序集,包括已经加载的和引用的未加载的dll, 但是获取的不是As...

查看KVM虚拟机IP

#!/bin/bash #ping当前网段内在线的主机,以便产生arp记录. subnet=`route -n|grep "UG" |awk '{print $2}'|sed 's/..$//g'` for ip in $subnet.{1..253};do { ping -c1 $ip >/dev/null 2>&1 }& d...

build-essential

linux操作系统上面开发程序, 光有了gcc 是不行的它还需要一个 build-essential软件包作用是提供编译程序必须软件包的列表信息 也就是说 编译程序有了这个软件包它才知道 头文件在哪 才知道库函数在哪还会下载依赖的软件包 最后才组成一个开发环境当然 build-essential包 安装时 需要的依赖包 有些你用不上 软件包: build-...

名称空间

一、函数对象 定义:函数名存放的就是函数的地址,所以函数名就是对象,称之为函数对象 可以直接被引用 可以当作函数参数传值 可以作为函数发返回值 可以作为容器类型的元素 def add(a,b): return a+b def low(a,b): return a-b def jump(a,b): return a*b def...

进程 PCB 进程挂起

7-1 进程定义  OS系统从只能跑一个程序到能跑多个。进程可以描述程序的执行过程。  进程:一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。  只有当一个程序被OS加载到内存中,cpu对其执行时,这个过程是动态的,称为进程。 7-2 进程的组成 包含了正在运行的一个程序的所有状态信息   程序的代码   程序处理的数据   要知道现在...