注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭研后台技术中心的博客

 
 
 
 
 

日志

 
 

避免python Popen阻塞  

来自wuyingxingzyd   2014-01-16 19:10:09|  分类: 运维 |举报 |字号 订阅

  下载LOFTER 我的照片书  |
很多开发和运维人员喜欢用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()
  评论这张
 
阅读(6452)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017