Heroku部署discord.py机器人报InterruptableThread无isAlive属性错误
问题描述
近期我参照教程为自己的discord.py机器人编写超时控制函数,避免单条命令执行耗时过长占用机器人资源,该命令依赖的逻辑在bot.py文件顶部导入的独立脚本中实现。
- 本地运行环境:Windows 10,微软商店安装的Python版本,执行
py bot.py启动时超时功能正常 - 部署环境:Heroku平台,通过
heroku run bash进入环境执行python bot.py启动后,触发calculator命令抛出如下错误:
Ignoring exception in command calculator: Traceback (most recent call last): (traceback...) AttributeError: 'InterruptableThread' object has no attribute 'isAlive' The above exception was the direct cause of the following exception: (more traceback...)
超时函数基于Python标准库threading实现,代码如下:
def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None): 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(): raise TimeLimitExpired() else: return it.result
函数调用方式如下,参数TIMEOUT值设为5:
timeout(interpreter.visit, (ast.node, context), timeout_duration=TIMEOUT, default=RuntimeResult().failure("Execution timed out."))
报错原因
报错是本地和Heroku环境的Python版本不一致导致的:
- 旧版Python(3.8及更早版本)的
threading.Thread类保留了驼峰命名的isAlive()方法作为兼容别名,本地安装的Python版本属于这个范围,所以代码可以正常运行 - 从Python 3.9版本开始,官方正式移除了已经废弃多年的
isAlive()别名,只保留符合PEP8规范的蛇形命名is_alive()方法。Heroku默认部署使用的Python版本为3.9+,因此找不到isAlive属性抛出AttributeError。
修复方案
直接将代码中判断线程存活状态的it.isAlive()替换为标准的it.is_alive()即可,该写法兼容所有仍在维护的Python版本,修复后的完整超时函数如下:
def timeout(func, args=(), kwargs={}, timeout_duration=1, default=None): 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.is_alive(): raise TimeLimitExpired() else: return it.result
补充说明:当前基于线程join的超时实现,仅能让主线程在超时后不再等待子线程返回,无法真正终止仍在后台运行的超时任务,长时间运行还是会占用资源。如果需要彻底终止超时任务,需要改用支持任务取消的协程方案或者多进程方案。
内容的提问来源于stack exchange,提问作者yees_7
相关产品推荐
相关产品推荐

