我发现了一个代码创建一个超时功能在这里 ,这似乎并没有工作。 完整的测试代码如下:
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秒内码结束。 问题出在哪儿?
一个线程将无法正常杀死另一个线程,所以你当前的代码, foo
永远不会终止。 (随着thread.daemon = True
当只有守护线程留在Python程序将退出,但是,这并不让你终止foo
而不同时终止主线程。)
有些人曾试图使用信号来停止执行,但是这可能是不安全的在某些情况下。
如果你可以修改foo
,有很多解决方案成为可能。 举例来说,你可以检查一个threading.Event
打出来的,而循环的。
但是,如果你不能修改foo
,你可以在使用一个子进程运行multiprocessing
因为与线程模块,子过程可以终止。 下面是如何可能看一个例子:
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'))
产量
('Hi', 1)
('Hi', 2)
('Hi', 3)
Bye
(2, 1)
(2, 2)
Sayonara
请注意,这有一定的局限性太大。
你需要把it
变成一个守护线程 :
it = ...
it.daemon = True
it.start()
否则,它的创建为用户线程,进程不会得到停止,直到所有的用户线程完成。
请注意,您的实现线程将继续运行,消耗你已经超时等待它即使资源。 CPython中的全局解释器锁可能进一步加剧的问题。