You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 10:57:33