如何在Windows平台强制执行Python中的超时函数

3 投票
2 回答
1137 浏览
提问于 2025-04-17 22:39

我想做的就是,如果一个函数在规定时间内没有返回,就让它超时。

事情的起因是,urllib2支持对urlopen设置超时,但在读取部分时却不支持,这导致我的程序卡住了。更改socket的defaulttimeout没有效果。使用signal.sigalrm也不行。我不想换成requests库,因为那样我得重写和测试很多代码。

我不想让一个线程去运行这个函数,然后再对线程设置超时,我想直接对这个函数设置超时。有没有什么好的办法?

2 个回答

0

是的,这个可以在Windows上实现,不需要信号,同时在其他操作系统上也能用。这里使用的是线程,但不是用来运行函数,而是用来设置超时的信号。具体的做法是创建一个新线程,等待一段时间,然后通过 _thread(在Python3中)或 thread(在Python2中)抛出一个异常。这个异常会在主线程中被抛出,如果发生了任何异常,with块就会退出。

import threading
import _thread   # import thread in python2
class timeout():
  def __init__(self, time):
    self.time= time
    self.exit=False

  def __enter__(self):
    threading.Thread(target=self.callme).start()

  def callme(self):
    time.sleep(self.time)
    if self.exit==False:
       _thread.interrupt_main()  # use thread instead of _thread in python2
  def __exit__(self, a, b, c):
       self.exit=True

使用示例:

with timeout(2):
    func()

在with块中的程序应该在2秒内完成,否则它将在2秒后被强制退出。

0

我喜欢在我的项目中使用David的这个类,在这里可以找到。我觉得它非常有效,而且它通过装饰器提供了一种简单的方法,可以在现有代码中实现。例如:

# Timeout after 30 seconds
@timeout(30)
def your_function():
    ...

注意:这个不是线程安全的!如果你在使用多线程,信号会被随机的线程捕获。不过对于单线程程序来说,这是最简单的解决方案。

撰写回答