0

假设我们有一个 python 函数magical_attack(energy),它可能会或可能不会持续超过一秒。它甚至可能是一个无限循环?我将如何运行,但如果它超过一秒钟,终止它,并告诉程序的其余部分。我正在寻找一个时尚的模块来做到这一点。例子:

import timeout
try: timout.run(magical_attack(5), 1)
except timeout.timeouterror:
    blow_up_in_face(wizard)

注意:无法修改功能。它在运行时来自外部。

4

2 回答 2

1

最简单的方法是在线程中运行后台代码:

t = threading.Thread(target=magical_attack, args=(5,))
t.start()
t.join(1)
if not t.isAlive():
    blow_up_in_face(wizard)

但是请注意,这不会取消magical_attack功能;即使您不再关心结果,它仍然可以在后台继续旋转多久。

安全地取消线程本质上很难做到,并且在每个平台上都不同,因此 Python 不会尝试提供一种方法来做到这一点。如果您需要,有以下三种选择:

  1. 如果您可以编辑代码magical_attack以每隔一段时间检查一个标志,您可以通过设置该标志来协同取消它。
  2. 您可以使用子进程而不是线程,然后可以安全地杀死它。
  3. 您可以使用ctypes, pywin32,PyObjC等来访问特定于平台的例程来终止线程。但是你必须真正知道你在做什么以确保你安全地做它,并且不要混淆 Python 做它。

正如 Chris Pak 所指出的,futuresPython 3.2+ 中的模块使这变得更加容易。例如,您可以在没有数千个线程的情况下放弃数千个作业;您可以将超时应用于整个作业组,就好像它们是单个作业一样;等等。另外,您可以通过简单的单行更改从线程切换到进程。不幸的是,Python 2.7 没有这个模块——但是有一个准官方的backport,你可以很容易地安装和使用它。

于 2013-08-29T21:04:21.047 回答
0

Abamert 在我准备的答案上击败了我,除了这个细节:

当且仅当外部函数通过 Python 解释器执行时,即使您无法更改它(例如,从已编译的模块),您也可以使用其他问题中描述的技术来杀死使用异常调用该函数的线程。

有什么方法可以杀死 Python 中的线程吗?

当然,如果您确实可以控制所调用的函数,则该答案中的 StoppableThread 类对此非常有效:

import threading

class StoppableThread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self):
        super(StoppableThread, self).__init__()
        self._stop = threading.Event()

    def stop(self):
        self._stop.set()

    def stopped(self):
        return self._stop.isSet()

class Magical_Attack(StoppableThread):
    def __init__(self, enval):
        self._energy = enval
        super(Magical_Attack, self).__init__()

    def run(self):
        while True and not self.stopped():
            print self._energy

if __name__ == "__main__":
    a = Magical_Attack(5)
    a.start()
    a.join(5.0)
    a.stop()
于 2013-08-29T21:16:43.720 回答