Windows可用但Termux无法运行的含nest_asyncio的Python Discord代码问题
问题描述
我有一段在Windows上可正常运行的Python代码:
import asyncio import nest_asyncio import discord import credentials discord_client = None loopHoleChannel = None task_discord = None telegram_client = None task_telegram = None class MyDiscordClient(discord.Client): async def on_ready(self): global loopHoleChannel loopHoleChannel = self.get_channel(1015386432900182056) def handle_discord(): print('Start:Discord.') global discord_client discord_client = MyDiscordClient(intents=discord.Intents.default()) discord_client.run(credentials.TOKEN) print('Complete:Discord.') async def async_main(): global task_discord task_discord = asyncio.create_task(handle_discord()) await task_discord def main(): nest_asyncio.apply() asyncio.run(async_main()) main()
但尝试在无Root权限的Termux中运行时,出现如下错误:
[Exception in callback <TaskStepMethWrapper object at 0x7b3e23db40>() handle: <Handle <TaskStepMethWrapper object at 0x7b3e23db40>()> Traceback (most recent call last): File "/data/data/com.termux/files/usr/lib/python3.10/asyncio/events.py", line 80, in _run self._context.run(self._callback, *self._args) RuntimeError: Cannot enter into task <ClientEventTask state=pending event=on_ready coro=<bound method MyDiscordClient.on_ready of <__main__.MyDiscordClient object at 0x7b3e1f24a0>>> while another task <Task pending name='Task-1' coro=<async_main() running at /data/data/com.termux/files/usr/RedsFiles/DiscordBots/TelegramToDiscordBot/main.py:33>> is being executed.]
我几乎可以确定问题出在nest_asyncio上,但移除它后代码也无法运行。
问题:我的判断是否正确?如果正确,如何在不使用nest_asyncio的情况下让代码正常运行?
解答
你的判断是正确的,问题根源确实是nest_asyncio。它用于允许嵌套运行asyncio事件循环,但discord.py的Client.run()本身会启动一个独立的事件循环,你把它封装到另一个async任务中执行,再加上nest_asyncio的适配逻辑,在Termux的Python环境下触发了任务执行的冲突。
要在不使用nest_asyncio的情况下正常运行,需要调整代码结构,避免嵌套事件循环:
- 核心思路:使用discord.py异步的
start()方法替代阻塞式的run(),让所有逻辑都在同一个顶层事件循环中调度
修改后的基础代码示例:
import asyncio import discord import credentials discord_client = None loopHoleChannel = None class MyDiscordClient(discord.Client): async def on_ready(self): global loopHoleChannel loopHoleChannel = self.get_channel(1015386432900182056) print(f"Discord已登录:{self.user}") async def main(): global discord_client discord_client = MyDiscordClient(intents=discord.Intents.default()) # 使用异步的start()方法,不会自行启动事件循环,由顶层asyncio.run()统一管理 await discord_client.start(credentials.TOKEN) if __name__ == "__main__": asyncio.run(main())
如果后续需要添加Telegram客户端这类其他异步逻辑,可以直接在main()中创建多个任务,通过asyncio.gather()统一调度:
async def main(): global discord_client, telegram_client # 初始化并启动Discord客户端任务 discord_client = MyDiscordClient(intents=discord.Intents.default()) discord_task = asyncio.create_task(discord_client.start(credentials.TOKEN)) # 初始化并启动Telegram客户端任务(示例框架) # telegram_client = YourTelegramClient() # telegram_task = asyncio.create_task(telegram_client.start()) # 等待所有异步任务完成 await asyncio.gather(discord_task)
这样修改后,代码仅启动一个顶层事件循环,所有异步任务都在该循环内调度,不会出现嵌套循环的冲突,也无需依赖nest_asyncio。
内容的提问来源于stack exchange,提问作者user17596589
相关产品推荐
相关产品推荐

