【问题标题】:Terminating a program within python在 python 中终止程序
【发布时间】:2016-03-31 03:30:53
【问题描述】:

您好,我在 python 代码中嵌入了时间约束,该代码正在运行带有函数的 fortran 代码。但是我意识到对另一个函数施加时间限制的函数不会终止代码,只是将其留在后台并跳过它。我想要做的是在代码超过限制时间时终止代码。这是我用来限制时间的代码,取自here

def timeout(func, args=(), kwargs={}, timeout_duration=15, default=1):
    import signal

    class TimeoutError(Exception):
        pass

    def handler(signum, frame):
        raise TimeoutError()

    # set the timeout handler                                                                                                                                             
    signal.signal(signal.SIGALRM, handler)
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
    finally:
        signal.alarm(0)

    return result

我查找了 popen.terminate()sys.exit()atexit.register(),但无法弄清楚它如何与我尝试在下面添加的这段代码一起工作,我在评论中显示。

...
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
#add the terminator
    finally:
...

注意:函数位于 for 循环链中,因此我不想终止整个 python 会话,而只想终止该函数运行的程序,该程序是一个 fortran 代码并跳到 for 循环链中的另一个元素。

在一些cmets和答案之后添加以下部分:

我尝试使用 popen.terminate() 添加 SIGTERM,但是它终止了所有 python 会话,我只想终止当前正在运行的会话并跳到 for 循环中的其他元素。我所做的如下:

...
    signal.signal(signal.SIGTERM, handler) 
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
        popen.terminate()
...

【问题讨论】:

  • 你说的“这个函数运行的程序”是什么意思?它是由subprocess 模块启动的外部进程吗?有后代进程吗?如果您发送 SIGTERM 信号,进程是否会退出?你的 Python 版本是什么?如果没有后代并且进程在SIGTERM 上退出,则将timeout 参数传递给process.wait() 并在TimeoutError 上调用process.terminate() 就足够了。
  • @J.F.Sebastian 此代码运行一个函数,该函数运行一个 fortran 代码,我想限制从 cpu 保存的运行时间。所有这个功能所做的就是将 fortran 代码留在后台并跳到 for 循环中的另一个元素,该循环在 100 个周期后堆积在 cpu 中,可以说,所以我想在跳到另一个元素之前终止会话。 Python 2.7 版。
  • @jackaraz 再次,“运行 fortran 代码”是否意味着您使用 subprocess 模块运行外部进程? (例如,numpy 库运行大量 fortran 代码无需启动新进程)。要限制并发进程的数量,请参阅this answer
  • @J.F.Sebastian 是的,我在另一个函数中使用 subprocess.check_output('./../bin/SPhenoUMSSM ../UMSSM/LH_out_'+mod+' > SPheno_log_'+mod, shell=True) 来运行 fortran 代码

标签: python popen terminate sys termination


【解决方案1】:

您不能期望引发异常的信号处理程序通过调用堆栈传播,它是在不同的上下文中调用的。

popen.terminate() 将在 posix 系统上生成 SIGTERM,因此您应该有一个用于 SIGTERM 而不是 SIGALRM 的信号处理程序。

与其在信号处理程序中引发异常,不如设置一些您定期检查的变量以停止活动。

或者,如果您没有SIGTERM 的信号处理程序,默认处理程序可能会生成KeyboardInterrupt 异常。

【讨论】:

  • 那么您是否建议将 popen.terminate() 与 SIGTERM 一起使用?因为您提出的替代方案听起来像,如果我理解正确,将终止我不想做的所有 python 会话,因为这部分位于 for 循环链中,所以我只想终止这个特定会话并继续处理中的其他元素for 循环。
  • 1- 异常确实会在主线程中传播。问题可能是func() 可能(由于错误)在其 C 代码中忘记在EINTR 上调用PyErr_CheckSignal(),因此在func() 将控制权返回给解释器之前不会调用Python 信号处理程序。 2-将 SIGTERM 发送到 python 进程有什么意义。看来 OP 想要终止一个子进程。 SIGALRM 的目的是中断 python 进程正在执行的任何操作,例如 process.wait()。 3-如果代码可以定期检查变量,那么除非代码在线程中;引发异常更容易
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多