gpt4 book ai didi

linux - Python子进程超时与耗时任务

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:33:55 34 4
gpt4 key购买 nike

下面的代码允许运行一个超时的子进程

p = subprocess.Popen([...])
while timeConsumedSoFar < timeoutLimit
if proc.poll() is not None:
doSomething
else:
time.sleep(2)
os.kill([...])

它适用于常规的 linux 命令。但是有些命令很耗时,比如'shred'

'shred [OPTIONS] FILE [...] '

粉碎逻辑卷可能需要 20 多分钟。有没有更好的方法来处理这个问题?

最佳答案

看起来 subprocess 处理等待中断,所以我不能使用它。

这是一个(可能有错误的)示例,它是更传统的 unix 方法。注意 这不会产生任何来自 stdout 的输出!事实上,它根本不产生任何输出。

由于所有评论,它看起来比实际情况更重要。

为什么您可能会认为这更好,因为我们不会持续对流程进行轮询。相反,如果命令完成,我们会告诉内核在指定超时后返回给我们。在任何一种情况下,响应都不会在事件发生后延迟超过几微秒,而且代码只需要设置第一个初始轮询。

#!/usr/bin/python

def runwait(timeout, *args):
from os import fork, execvp, waitpid, kill, dup2
from signal import alarm, signal, SIGTERM, SIGALRM, SIG_DFL
from errno import EINTR

## We dont do much in the alarm handler, we only care that we interrupted
## the wait() on the process.
def onalarm(sig, frame):
pass

## This is used for redirecting stdin/out/err to /dev/null
devnull = open('/dev/null', 'r+')
pid = fork()
if not pid:
## The child process. Begin by redirecting all input and output.
dup2(devnull.fileno(), 0)
dup2(devnull.fileno(), 1)
dup2(devnull.fileno(), 2)
## Probably not a great idea to pass this file descriptor to whatever we
## end up executing.
devnull.close()

## Overwrite child process with new execution context.
execvp(args[0], args)
## If something failed (like command not found) exit 63. WARNING, because we
## redirected all output to /dev/null, you WILL NOT be informed the command was
## not found directly. Use the exit code to work that out.
sys.exit(63)

## This is the parent process that initiated the fork.
## Arm a timer using timeout given by first parameter of function. This
## must be an int, not a float. I dont bother checking though cause I'm lazy.
signal(SIGALRM, onalarm)
alarm(timeout)

## We wait on the pid, this call typically blocks forever.
try:
pid, rc = waitpid(pid, 0)
except OSError as e:
## We will land here if the alarm triggered BEFORE the process completed!
## In this case, if we were interrupted to deal with the
## signal handler its definitely an alarm. Otherwise
## a peripheral exception occurred (permissions for example) so just re-raise the exception.
if e.errno == EINTR:
## We send a TERM signal to terminate the process and re-wait. This causes
## wait to (under normal conditions) come back immediately with the signal
## we just killed it with which parse out further down.
kill(pid, SIGTERM)
pid, rc = waitpid(pid, 0)
else:
raise

## Waits status is a 16bit integer packing a 8bit signal and 8bit return code.
## Do some funky bitwise operations to separate the two..
sig = rc & 0xff
rc >>= 8
## Whatever happened above, always disable the alarm and signal handling.
alarm(0)
signal(SIGALRM, SIG_DFL)
return sig, rc


if __name__ == "__main__":
# An example when you time out
print runwait(2, "sleep", "20")
# An example on success
print runwait(5, "sleep", "3")
# More success, but demonstrating no output
print runwait(5, "grep", "root", "/etc/passwd")

该函数返回终止进程的信号号(如果有)和执行程序的返回码。

关于linux - Python子进程超时与耗时任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22873633/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com