避免python Popen阻塞

http://backend.blog.163.com/blog/static/2022941262014016710912/


很多开发和运维人员喜欢用python做一些开发或是运维的工作。不可避免要调用系统命令。


调用系统命令的方式有两种,一种是os.system(CMD),一种是subprocess.Popen(CMD,stdout=what,stderr=what)。

如:
import os
os.system("echo hi")

或者
import subprocess
obj=subprocess.Popen("echo hi")

但是这通常不能满足要求。我们一般需要解析执行命令之后的输出,并从输出中解析出我们想要的信息。

前一种无法满足要求,os.system无法有效输出cmd执行之后的结果。只能使用subprocess的方式。

通常的做法如下:



import subprocess
import traceback

try:
    cmd = "ls -lh"
    obj = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
    obj.wait()
    
    lines = obj.stdout.readlines()
    
    if not lines or len(lines) == 0:
        line = obj.stderr.readlines()
    
    print lines
except Exception, e:
    print traceback.format_exc()


这样做在大多数情况下都不会有问题。但是这里影藏了潜在的危险!就是会发现有一天程序hang住了。
这可能导致整个应用被挂住。当你费了很大力气定位问题时,会发现罪魁祸首便是Popen。而令人困惑的
是,这个地方你已经测试过n次了。怎么会在这里hang住了呢?

原因是subprocess的PIPE是有大小的。在python2.6.11之前,PIPE的大小为文件页的大小(i386上是4096),
2.6.11之后变为65536.因此当输出内容超过65536,会引起阻塞。因为PIPE已经被塞满了,无法再塞进更多的
数据。

解决方法是不用subprocess提供的PIPE,而是使用自己创建的流。如此,可以控制流的大小。不多说,直接
上代码:
import subprocess
import traceback
import tempfile
try:
    cmd = "ls -lh"
    out_temp = tempfile.SpooledTemporaryFile(bufsize=10*1000)
    fileno = out_temp.fileno()
    obj = subprocess.Popen(cmd,stdout=fileno,stderr=fileno,shell=True)
    obj.wait()
    
    out_temp.seek(0)
    lines = out_temp.readlines()
    
    
    print lines
except Exception, e:
    print traceback.format_exc()
finally:
    if out_temp:
        out_temp.close()

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值