在具有最大时间限制的循环中运行外部程序

时间:2011-04-25 16:20:09

标签: python

我希望有一个python脚本,它在循环中顺序运行外部程序。我还想将程序的每次执行限制为最大运行时间。如果超过,则终止该程序。完成此任务的最佳方法是什么?

谢谢!

2 个答案:

答案 0 :(得分:4)

要从Python运行外部程序,通常需要使用subprocess module

您可以使用os.fork()os.execve()(或其中一个exec*表兄弟)“滚动您自己的”子流程处理......以及您喜欢的任何文件描述符管道和信号处理魔法。但是,subprocess.Popen()功能已经实现并公开了您想要为您做的事情的大部分功能。

要安排程序在给定的一段时间后死亡,您可以让Python脚本在超时后终止它。当然,您需要检查过程是否已经完成。这是一个愚蠢的例子(使用shlex module中的split函数以增加可读性:

from shlex import split as splitsh
import subprocess
import time

TIMEOUT=10
cmd = splitsh('/usr/bin/sleep 60')
proc = subprocess.Popen(cmd)
time.sleep(TIMEOUT)
pstatus = proc.poll()
if pstatus is None:
    proc.kill()
# Could use os.kill() to send a specific signal
# such as HUP or TERM, check status again and 
# then resort to proc.kill() or os.kill() for
# SIGKILL only if necessary

如上所述,有几种方法可以杀死你的子进程。请注意,我检查“is None”而不是测试pstatus的真相。如果您的流程以退出值零(通常表示没有发生错误)完成,那么对proc.poll()结果的简单测试会将完成与仍在运行的流程状态混为一谈。

还有一些方法可以确定是否已经过了足够的时间。在这个例子中我们睡觉,如果还有其他我们可以做的事情,这有点傻。这只是让我们的Python进程(你的外部程序的父进程)闲置。

您可以使用time.time()捕获开始时间然后启动您的子进程,然后执行其他工作(例如,启动其他子进程)并检查时间(可能在其他活动的循环中),直到您想要的超时为止已超出。

如果您的任何其他活动涉及文件或套接字(网络)操作,那么您需要考虑使用select module作为返回可读,可写或准备好的文件描述符列表的方法“特殊的“事件。 select.select()函数还采用可选的“超时”值。对select.select([],[],[],x)的调用与time.sleep(x)基本相同(如果我们没有提供任何文件描述符供它选择)。

代替select.select(),也可以使用fcntl模块将文件描述符设置为非阻塞模式,然后使用os.read()(不是普通文件对象{{ 1}}方法,但来自os module的低级功能。同样,最好在可能的情况下使用更高级别的接口,并且只在必要时使用较低级别的功能。 (如果使用非阻塞I / O,则必须在异常处理块中完成所有.read()或类似操作,因为Python将“-EWOULDBLOCK”条件表示为OSError(异常),如:“OSError: [Errno 11]资源暂时不可用“(Linux)。错误的精确数量可能因操作系统而异。但是,它应该是可移植的(至少对于POSIX系统)使用来自的os.read()值。 errno module

(我意识到我在这里遇到了一个rathole,但是关于你的程序如何在你的子进程运行外部程序时做一些有用的事情的信息是如何管理它们的超时的自然延伸。)

过去曾讨论过有关非阻塞文件I / O的丑陋细节(包括MS Windows的可移植性问题):Stackoverflow: non-blocking read on a stream in Python

正如其他人所评论的那样,最好提供更详细的问题,并提供简短,专注的代码片段,以显示您已经采取的措施。通常你不会发现这里的人倾向于写教程而不是答案。

答案 1 :(得分:1)

如果您能够使用Python 3.3

来自docs

subprocess.call(args,*,stdin = None,stdout = None,stderr = None,shell = False, timeout = None)

  
    
      

subprocess.call([“ls”,“ - l”])       0

             

subprocess.call(“exit 1”,shell = True)       1

    
  

应该做的伎俩。