线程无法优雅地杀死另一个线程,因此对于您当前的代码,foo永远不会终止。 (随着thread.daemon = True当只有守护线程留在Python程序将退出,但是,这并不让你终止foo没有也终止主线程。)
Some people曾尝试使用信号来停止执行,但是这可能是有些情况下为unsafe。
如果您可以修改foo,则可能有许多解决方案。例如,你可以检查一个threading.Event跳出while循环。
但是,如果您无法修改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
注意,这有一定的局限性太大。
子过程接收的父进程的变量的副本。如果修改子进程中的某个变量,将会影响 父进程NOT。如果您的功能func需要修改变量,则需要使用shared variable。
参数(通过args)和关键字(kwds)必须是 可挑选。
进程比线程更占用资源。通常,只有 想要在 程序的开头创建一个多处理池。这个timeout函数会在您每次调用它时创建一个Pool。这是必要的,因为我们需要pool.terminate()到 终止foo。可能有更好的方法,但我没有想到它。