您的位置:首页 > 编程语言 > Python开发

避免python Popen阻塞

2015-09-01 16:38 405 查看
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()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: