Python subprocess注意问题

最近写了个脚本,需要执行第三方程序,并根据程序输出判断执行情况,当程序执行时间过长时kill该进程。因此选用了subprocess模块。

process = subprocess.Popen(self.cmd,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True ,close_fds=True)

1. 在linux下,不加参数 shell=True 会报错

2. 当没有参数 close_fds=True 时,打开的标准输入、标准输出、标准错误不会被关闭,当打开的文件数量超过最大值时会产生“OSError: [Errno 24] Too many open files”异常。(但也有人说不起作用需要自己关闭标准输入、标准输出、标准错误,但是暂时没有发现这种情况)

3. 当不使用process.terminate()终止进程后,再使用process.kill(),会导致进程kill失败

4. 开始使用process.stdout.readline()在子线程中循环读取管道内容,虽然中间有sleep但也十分消耗资源。(后改为进程结束时使用process.stdout.read()读取全部内容)

记录下来防止时间长了,忘记了。不对的地方还请指正。。。

#coding=utf-8
'''
Created on 2015-8-13

@author: xhw

@explain: pass(添加返回索引输出内容:给合并索引模块使用,判断是否合并成功)
'''
import time
import subprocess
import threading
import common.logger as log 
from common.traceback_error import get_err_msg
from common.MailHandler import SendMail
import sys,os,shutil
system = sys.platform
Maxtime = 999999
reload(sys)
sys.setdefaultencoding('utf-8')

class CmdServer:
    
    def __init__(self,cmd,timeout,taskname):
        ''' 
        @cmd:命令字符串
        @timeout:任务超时时间(进程运行超过该时间,kill该进程)
        @taskname:任务名称(根据该任务名称记录命令输出信息)
        '''
        print cmd,timeout,taskname,time.strftime("%Y-%m-%d %H:%M:%S")
        self.cmd = cmd
        if timeout:
            self.timeout = int(timeout)
        else:
            self.timeout = Maxtime
        self.path = os.path.join(os.path.dirname(__file__),'cmd_stdout')
        self.stdoutfile = os.path.join(self.path,taskname + '.txt')
        self.renamefile = os.path.join(self.path,taskname + '1.txt')
        
    
    def run(self):
        self.writeStdout(self.cmd+'\n')
        try:
            #在windows下运行非shell命令时,使用shell=True,不能使子进程结束(linux下没有测试)
            process = subprocess.Popen(self.cmd,stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, shell=True ,close_fds=True)
            num = 0
            while process.poll() == None:
                if num >= self.timeout:
                    self.writeStdout(u"任务超时!\n")
                    try:
                        process.terminate()
                        stdout = self.readStdout(process)
                        process.kill()
                        process.wait()
                        self.writeStdout(u"任务kill!\n")
                        return False,"Task running timeout!"+str(stdout)
                    except:
                        errmsg = get_err_msg()
                        log.CmdRun_Logger.error(errmsg)
                        self.writeStdout(u"任务kill失败!\n")
                        SendMail(subject = 'command_worker', content = errmsg)
                        return False,"Task running timeout,Kill failure"+str(stdout)
                time.sleep(1)
                num+= 1
                        
            if process.poll() is not None:
                self.writeStdout(u"任务结束!\n")
                stdout = self.readStdout(process)
                process.wait()
                return True,stdout
        except:
            errmsg = get_err_msg()
            log.CmdRun_Logger.error(errmsg)
            SendMail(subject = 'command_worker', content = errmsg)
            return False,errmsg
        
    def readStdout(self,process):
        ''' 读取执行命令进程输出的内容,并写入日志文件'''
        stdout = ""
        try:
            stdout = process.stdout.read()
            if stdout:
                if 'win' in system:
                    stdout = stdout.decode('gbk','ignore').encode('utf-8') 
                self.writeStdout(stdout)
        except:
            errmsg = get_err_msg()
            log.CmdRun_Logger.error(errmsg)
            SendMail(subject = 'command_worker', content = errmsg)
        return stdout
    
    def writeStdout(self,stdout):
        ''' 记录命令输出'''
        try:
            stdout = stdout.strip()
            with open(self.stdoutfile, 'a+') as f:
                f.write(stdout+'\r\n')
        except:
            errmsg = get_err_msg()
            log.CmdRun_Logger.error(errmsg)
            SendMail(subject = 'command_worker', content = errmsg)
        self.checklogfile()
        
    def checklogfile(self):
        ''' 这里使用日志模块并不清楚会有那些任务,所以没有使用配置文件,但不使用配置文件,会在日志文件设置上出现问题,
                        在这里自己替换超过大小到日志文件(默认两个日志文件,每个10M)'''
        if not os.path.exists(self.stdoutfile):
            return
        if os.path.getsize(self.stdoutfile) > 1024*1024*10:
            try:
                print self.stdoutfile, self.renamefile
                #os.rename(self.stdoutfile, self.renamefile)#会提示WindowsError: [Error 32],不清楚是不是OS模块操作文件没有关闭引起的
                shutil.copyfile(self.stdoutfile, self.renamefile)
                with open(self.stdoutfile,'w') as f:
                    f.write(time.strftime('%Y-%m-%d %H:%M:%S'+'\r\n'))
            except:
                errmsg = get_err_msg()
                log.CmdRun_Logger.error(errmsg)
                SendMail(subject = 'command_worker', content = errmsg)
        
        
        
        

if __name__ == '__main__':
    A = CmdServer(r'python E:\work\sphinx_task\test_task\test3.py',50,'test3')
    A.run()            


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值