gpt4 book ai didi

python - 在 python 中使用线程的超时函数不起作用

转载 作者:太空狗 更新时间:2023-10-29 21:32:12 24 4
gpt4 key购买 nike

我找到了创建超时函数的代码 here ,这似乎不起作用。完整的测试代码如下:

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。)

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

请注意,这也有一些限制。

  • 子进程接收父进程变量的副本。如果您修改子流程中的变量,它不会影响父进程。如果您的函数 func 需要修改变量,您将需要使用 shared variable

  • 参数(通过args)和关键字(kwds)必须是可酸洗。

  • 进程比线程占用更多资源。通常,你只想要在开始时创建一个多处理池程序。此 timeout 函数会在您每次调用它时创建一个 Pool。这是必要的,因为我们需要 pool.terminate() 来终止 foo。可能有更好的方法,但我还没想到。

关于python - 在 python 中使用线程的超时函数不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13821156/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com