在Python中正确地设置代码超时执行的方法

34 投票
10 回答
21439 浏览
提问于 2025-04-16 22:55

我在网上查了一下,发现有一些讨论和ActiveState的做法,关于如何在代码运行时设置超时。看起来有几种常见的方法:

  • 使用线程来运行代码,然后用join方法加上超时。如果超时了,就杀掉这个线程。不过,这种方法在Python中并不直接支持(用了私有的_Thread__stop函数),所以这被认为是不好的做法
  • 使用signal.SIGALRM - 但这种方法在Windows上不管用
  • 使用子进程并设置超时 - 但这太重了,如果我想经常启动可以中断的任务,我可不想每次都启动一个新进程!

那么,什么才是正确的方法呢?我不是在问变通的方法(比如使用Twisted和异步IO),而是想知道解决实际问题的真正方法 - 我有一个函数,想要在设定的超时时间内运行。如果超时了,我想要控制权返回。而且我希望这个方法在Linux和Windows上都能用。

10 个回答

6

如果是网络相关的问题,你可以试试:

import socket
socket.setdefaulttimeout(number)
12

你可能在寻找的是 multiprocessing 模块。如果 subprocess 对你来说太复杂了,那么这个模块可能也不太适合你。

import time
import multiprocessing

def do_this_other_thing_that_may_take_too_long(duration):
    time.sleep(duration)
    return 'done after sleeping {0} seconds.'.format(duration)

pool = multiprocessing.Pool(1)
print 'starting....'
res = pool.apply_async(do_this_other_thing_that_may_take_too_long, [8])
for timeout in range(1, 10):
    try:
        print '{0}: {1}'.format(duration, res.get(timeout))
    except multiprocessing.TimeoutError:
        print '{0}: timed out'.format(duration) 

print 'end'
12

其实,这个问题没有一个通用的解决办法。你得根据具体情况来选择合适的解决方案。

  • 如果你想给自己完全控制的代码设置超时,你需要让代码能够配合工作。这段代码必须能够以某种方式分成小块,就像在事件驱动的系统中那样。如果你能确保没有任何东西会长时间占用锁,也可以通过多线程来实现,但处理锁其实挺复杂的。

  • 如果你想设置超时是因为你担心代码失控(比如,你担心用户会让你的计算器计算 9**(9**9)),那么你需要在另一个进程中运行它。这是唯一一个简单的方法来确保它的隔离。把它放在你的事件系统里或者甚至是另一个线程里都不够安全。虽然也可以像之前那样把代码分成小块,但这需要非常小心的处理,通常也不值得;而且,这样做也不能完全做到和直接运行Python代码一样的效果。

撰写回答