我发现了一个代码创建一个超时功能在这里,这似乎并没有工作.完整的测试代码如下:
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)
Run Code Online (Sandbox Code Playgroud)
预期行为:代码在3秒内结束.问题出在哪儿?
线程无法正常杀死另一个线程,因此使用当前代码foo永远不会终止.(thread.daemon = True当只剩下守护程序线程时,Python程序将退出,但是这不允许在foo不终止主线程的情况下终止.)
有些人试图使用信号来停止执行,但在某些情况下这可能是不安全的.
如果您可以修改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'))
Run Code Online (Sandbox Code Playgroud)
产量
('Hi', 1)
('Hi', 2)
('Hi', 3)
Bye
(2, 1)
(2, 2)
Sayonara
Run Code Online (Sandbox Code Playgroud)
请注意,这也有一些限制.
子进程接收父进程变量的副本.如果修改子流程中的变量,则不会影响父流程.如果您的函数func需要修改变量,则需要使用共享变量.
参数(传递args)和keywords(kwds)必须是可选择的.
timeout函数都会创建一个Pool.这是必要的,因为我们需要pool.terminate()终止foo.可能有更好的方法,但我没有想到它.| 归档时间: |
|
| 查看次数: |
10279 次 |
| 最近记录: |