Python使用asyncio结合threading.Timer出现协程未等待报错如何解决
问题排查
- 递归逻辑与语法错误:
send_chat内部将自身作为任务创建后执行await t(),会形成无限递归循环,永远执行不到后续定时器逻辑;且asyncio.Task类型的任务对象不可直接加括号调用,await t()属于语法错误,正确写法为await t。
- 递归逻辑与语法错误:
- 跨线程协程调用错误:
threading.Timer是同步线程工具,回调函数运行在独立同步线程中,直接给定时器传入协程/异步任务对象时,线程不会自动await协程,直接触发「协程未被等待」的报错;同时asyncio事件循环不是线程安全的,不可在其他线程直接操作当前线程的事件循环。
- 跨线程协程调用错误:
- 依赖遗漏:代码未导入
random库,bot对象也没有提前声明初始化,运行时会额外触发名称错误。
- 依赖遗漏:代码未导入
- 业务逻辑缺失:
send_chat中完全没有调用发消息的Send_GP方法,定时器触发后也不会执行预期的发消息逻辑。
- 业务逻辑缺失:
修复方案
优先推荐纯异步实现定时逻辑,无需混线程,复杂度更低:
import asyncio, redis, random # 此处补充你原有bot对象的初始化逻辑 db = redis.StrictRedis(host='localhost', port=6379, db=0, charset='UTF-8', decode_responses=True) txts = ['txt1','txt2','txt3'] async def Send_GP(): async for dialog in bot.iter_dialogs(): if dialog.is_group: text = random.choice(txts) await bot.send_message(dialog.id, text) async def send_chat(): while True: try: # 执行发消息逻辑 await Send_GP() # 读取定时间隔 interval = int(db.get('time_chat:')) db.setex('timeleft:', interval, True) # 异步等待间隔时间后自动执行下一轮,替代Timer await asyncio.sleep(interval) except Exception as e: print(e) # 启动异步任务 if __name__ == "__main__": loop = asyncio.get_event_loop() loop.create_task(send_chat()) loop.run_forever()
如果必须使用threading.Timer实现,需要正确处理跨线程协程提交逻辑:
import asyncio, redis, random from threading import Timer # 此处补充你原有bot对象的初始化逻辑 db = redis.StrictRedis(host='localhost', port=6379, db=0, charset='UTF-8', decode_responses=True) txts = ['txt1','txt2','txt3'] # 提前获取主线程的事件循环供跨线程调用 loop = asyncio.get_event_loop() async def Send_GP(): async for dialog in bot.iter_dialogs(): if dialog.is_group: text = random.choice(txts) await bot.send_message(dialog.id, text) # 跨线程提交协程到事件循环的适配方法 def run_async_task(coro): asyncio.run_coroutine_threadsafe(coro, loop) async def send_chat(): try: # 执行发消息逻辑 await Send_GP() interval = int(db.get('time_chat:')) db.setex('timeleft:', interval, True) # 定时器回调通过适配方法提交协程 Timer(interval, run_async_task, args=(send_chat(),)).start() except Exception as e: print(e) if __name__ == "__main__": loop.create_task(send_chat()) loop.run_forever()
内容的提问来源于stack exchange,提问作者REZA TG
相关产品推荐
相关产品推荐

