运行子进程时检查条件

时间:2014-03-06 14:36:18

标签: python subprocess

我正在使用subprocess.Popen()执行命令。我想在执行剩下的代码之前等待进程完成但同时我想在运行子进程2分钟后检查生成的文件的状态。如果文件的大小为零,那么我想停止该过程。目前我的代码如下。有没有更聪明的方法呢?

  def execute(command,outputfilename):
    process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    start_time=time.time()
    Is_Working=False
    while True:
     process.poll()
     if not Is_Working:
         #allow 2 minutes for the process to create results
         if process.returncode == None and (time.time()-start_time)//60>1:
             Is_Working=True
             if (os.stat(outputfilename)[6]==0):
                 process.kill()
                 return
     if process.returncode != None: 
         break

    output, errors=process.communicate()

2 个答案:

答案 0 :(得分:1)

全球你的代码对我来说很好。只有几个细节:

  1. (time.time()-start_time)//60>1中,我认为使用//是无用的,因为你不一定需要对结果进行平局,并将整数转换为除法的lhs的结果。保持全部浮动应该可以进行比较,这是所有基本的机器逻辑;
  2. 通过使用while process.returncode is not None:…
  3. 更改循环条件,可以避免从无限循环中断
  4. 为了使它更简单,我实际上会循环直到文件大小为!=0,然后在循环之后调用process.wait()
  5. 这将是使用while/else构造
  6. 的好方案

    所以,一个改进是,所以你可以在过程完成后做任务(比如清理或重试......)(无论是成功还是失败):

    def execute(command,outputfilename):
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        start_time=time.time()
        Is_Working=False
        while process.returncode == None:
            process.poll()
            #allow 2 minutes for the process to create results
            if (time.time()-start_time)/60 > 1:
                if (os.stat(outputfilename)[6]==0):
                    process.kill()
                    break
        else:
            # the process has not been killed
            # wait until it finishes
            process.wait()
            output, errors=process.communicate()
            # do stuff with the output
            […]
    
        # here the process may have been killed or not
        […]
    

    或另一个好的选择是提出例外:

    def execute(command,outputfilename):
        process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        start_time=time.time()
        Is_Working=False
        while process.returncode == None:
            process.poll()
            #allow 2 minutes for the process to create results
            if (time.time()-start_time)/60 > 1:
                if (os.stat(outputfilename)[6]==0):
                    process.kill()
                    raise Exception("Process has failed to do its job")
        # the process has not been killed
        # wait until it finishes
        process.wait()
        output, errors=process.communicate()
        # do stuff with the output
        […]
    

    HTH

答案 1 :(得分:0)

如果outputfilename为空(我假设某些外部流程修改了outputfilename),要在2分钟内终止子流程,您可以使用threading.Timer

import os
from subprocess import Popen, PIPE
from threading import Timer

def kill_if_empty(proc, filename):
    if proc.poll() is None and os.path.getsize(filename) == 0:
       proc.kill()

def execute(command, outputfilename):
    p = Popen(command, stdout=PIPE, stderr=PIPE)
    Timer(2*60, kill_if_empty, [p, outputfilename]).start()
    output, errors = p.communicate()
    ...

此代码分别收集stdout / stderr,它避免了问题中代码中可能存在的死锁。