Timeout function using threading in python does not work
我在这里发现了一个创建超时函数的代码,它似乎不起作用。完整的测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None): import threading class InterruptableThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.result = None def run(self): try: self.result = func(*args, **kwargs) except: self.result = default it = InterruptableThread() it.start() it.join(timeout_duration) if it.isAlive(): return default else: return it.result def foo(): while True: pass timeout(foo,timeout_duration=3) |
预期行为:代码在3秒内结束。问题出在哪里?
一个线程不能优雅地杀死另一个线程,因此使用当前代码,
有些人试图用信号来停止执行,但在某些情况下这可能是不安全的。
如果您可以修改
但是,如果不能修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import time import multiprocessing as mp def foo(x = 1): cnt = 1 while True: time.sleep(1) print(x, cnt) cnt += 1 def timeout(func, args = (), kwds = {}, timeout = 1, default = None): pool = mp.Pool(processes = 1) result = pool.apply_async(func, args = args, kwds = kwds) try: val = result.get(timeout = timeout) except mp.TimeoutError: pool.terminate() return default else: pool.close() pool.join() return val if __name__ == '__main__': print(timeout(foo, kwds = {'x': 'Hi'}, timeout = 3, default = 'Bye')) print(timeout(foo, args = (2,), timeout = 2, default = 'Sayonara')) |
产量
1 2 3 4 5 6 7 | ('Hi', 1) ('Hi', 2) ('Hi', 3) Bye (2, 1) (2, 2) Sayonara |
请注意,这也有一些限制。
子进程接收父进程变量的副本。如果修改子流程中的变量,它不会影响父进程。如果函数
func 需要修改变量,则需要使用共享变量。参数(通过
args 传递)和关键字(kwds 传递)必须为可腌制的- 进程比线程资源更重。通常,只有你希望在程序。这个
timeout 函数每次调用时都创建一个Pool 。这是必要的,因为我们需要pool.terminate() 来终止foo 。也许还有更好的办法,但我没想到。
您需要将
1 2 3 | it = ... it.daemon = True it.start() |
否则,它被创建为一个用户线程,在所有用户线程完成之前,进程不会停止。
请注意,使用您的实现,线程将继续运行并消耗资源,即使您已经超时等待它。CPython的全局解释器锁可能进一步加剧这个问题。