简体   繁体   English

运行子流程时检查条件

[英]Check a condition while running subprocess

I am executing a command using subprocess.Popen(). 我正在使用subprocess.Popen()执行命令。 I want to wait for the process to finish before executing the rest of my code but at the same time I would like to check the status of the produced files after 2 min of running the subprocess. 我想在执行其余代码之前等待进程完成,但是同时我想在运行子进程2分钟后检查生成的文件的状态。 If the size of file is zero then I want to stop the procedure. 如果文件大小为零,那么我想停止该过程。 Currently my code is as below. 目前,我的代码如下。 Is there any smarter way to do this? 有没有更聪明的方法可以做到这一点?

  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()

globally your code looks good to me. 在全球范围内,您的代码对我来说看起来不错。 Only a few details: 只有一些细节:

  1. in (time.time()-start_time)//60>1 , I think there's a useless use of // , as you do not necessarily need to floor the result, and convert to integer the result of the lhs of the division. (time.time()-start_time)//60>1 ,我认为//没用,因为您不一定需要舍弃结果并将除法lhs的结果转换为整数。 keeping it all float should be ok for the comparision, it's all basic machine logic ; 比较起来应该保持所有浮动,这是所有基本的机器逻辑;
  2. you could avoid to break from an infinite loop, by changing the loop condition with while process.returncode is not None:… 您可以通过使用while process.returncode is not None:…来更改循环条件来避免从无限循环中中断while process.returncode is not None:…
  3. to make it even simpler, I'd actually loop until the file size is !=0 and then call process.wait() just after the loop. 为了使它更简单,我实际上要循环直到文件大小为!=0 ,然后在循环之后调用process.wait()
  4. which would then be a good scenario for using the while/else construct 这将是使用while/else构造的好方案

So, one improvement would be, so you can do stuff (like cleanup or retry…) after the process has finished (whether it succeeded or failed): 因此,有一个改进是,您可以在过程完成之后(无论成功还是失败)进行处理(例如清理或重试...):

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
    […]

or the other good option would be to raise an exception: 或另一个好的选择是引发异常:

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 HTH

To kill the child process in 2 minutes if outputfilename is empty (I assume outputfilename is modified by some external process), you could use threading.Timer : 要在outputfilename为空的情况下在2分钟内杀死子进程(我假设outputfilename被某个外部进程修改了),则可以使用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()
    ...

This code collects stdout/stderr separately and it avoids a possible deadlock that is present in your code in the question. 此代码分别收集stdout / stderr,并且避免了问题代码中可能出现的死锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM