使用多线程使块的执行超时

时间:2019-07-11 11:14:01

标签: python multithreading python-2.7 performance

我有一个课在做一些可能要花很长时间的工作,所以我需要实现一个超时。有问题的方法分解为几种方法,这些方法也都分解了。所有这些都可能很慢,因此我们也需要超时。检查它们每个中的时间只会污染代码,所以我提出了以下解决方案:

class Runner:
    def __init__(self, *args, **kwargs):
        # init...
        self.start = None
        self.timeout = 60  # 1 minute for instance
        self.timedout = False

    def countdown():
        while not self.timedout:
            self.timedout = time.time() - self.start > self.timeout

    def run():
        # stuff
        self.start = time.time()
        t = multithreading.Thread(target=self.countdown)
        t.start()
        # do various things, call the chain of methods...
        t.join()

然后我们只需在相关方法中检查self.timedout

我知道我本可以使用multiprocessing并将整个运行块包装到一个有超时的进程中,但是(a)我需要微调退出方法的位置,我不能只是中断处理,因为这可能会弄乱状态,并且(b)由于出现了一些泡菜错误,我什至似乎都无法使用Process

我关心的是coundown方法:调用time.time()是否会影响性能?我正在考虑例如休眠线程在while循环中1秒。但是话又说回来,我不确定使线程休眠的实际机制如何影响性能。如果只影响正在运行的线程的性能,那我很好,但是如果它影响整个执行,那就不好了。

2 个答案:

答案 0 :(得分:0)

join()函数接受一个可选参数,该参数是超时值。您可以设置一个超时值t.join(no_of_seconds),如果该过程运行完毕或超过超时阈值,则该过程将返回。使用t.isAlive()检查进程是否仍在运行,终止进程并在此之后设置班级超时字段。

答案 1 :(得分:0)

threading中的循环不断运行当然是不希望的。让它长时间睡眠是一件好事,因为这会挂起调用线程并允许将它本来可以分配给其他任务的周期使用。
但是,我也认为它不会对您的工作造成过度损害整体表现。

仍然,我建议改用Timer模块中的Timer

  

此类表示仅应在   一定时间已过去-一个计时器。 Thread是的子类   run [...]

Timer.cancel()允许在计时器仍处于等待状态时停止计时器(尽管此后可以调用它而没有任何效果)。这样可以使self.timedout方法在超时间隔过去之前结束,并且class Runner: def __init__(self): self.timedout = False self.timeout_sec = 60 def _set_timeout(self): self.timedout = True def run(self): timer = Timer(self.timeout_sec, function=self._set_timeout) timer.start() # do various things, call the chain of methods... timer.cancel() 在没有超时的情况下保持为假。

_set_timeout

使用lambda可以摆脱var = True方法。不过,这似乎有些笨拙。由于lambda的主体必须是表达式,而setattr是语句,因此必须使用timer = Timer(self.timeout_sec, function=lambda inst: setattr(inst, "timedout", True), args=(self,)) 并将实例传递给lambda:

self.timedout

另一种选择是将self.timedout = Event() [...] timer = Timer(self.timeout_sec, function=lambda to: to.set(), args=(self.timedout,)) 设为Event并调用其set()方法来发出超时信号。

if self.timedout.is_set():
    [...]

然后通过Event.is_set()检查是否发生超时事件:

elasticsearch.url