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

Discord Bot控制台输入报错求助:事件循环被input阻塞

问题描述

我和朋友开发项目时,希望运行!setup命令后,能通过控制台输入内容让Discord Bot发送到聊天里。我们写的代码如下:

import discord
from discord.ext import commands

intents = discord.Intents.all()
bot = commands.Bot(command_prefix="!", intents=intents)

@bot.event
async def on_ready():
    print("Logged in as {}".format(bot.user))
@bot.command()
async def setup(ctx):
    await ctx.message.delete()
    while True:
        msg = input("Message to send: ")
        ctx.send(msg)

运行后报错:

Loop thread traceback (most recent call last):
  File "C:\Users\bobot\OneDrive\Documents\projs\py\penissie.py", line 128, in <module>
    bot.run(token)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\client.py", line 860, in run
    asyncio.run(runner())
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 190, in run
    return runner.run(main)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 640, in run_until_complete
    self.run_forever()
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\windows_events.py", line 321, in run_forever
    super().run_forever()
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 607, in run_forever
    self._run_once()
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\base_events.py", line 1922, in _run_once
    handle._run()
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\asyncio\events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\client.py", line 441, in _run_event
    await coro(*args, **kwargs)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1395, in on_message
    await self.process_commands(message)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1392, in process_commands
    await self.invoke(ctx)  # type: ignore
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\bot.py", line 1350, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\core.py", line 1029, in invoke
    await injected(*ctx.args, **ctx.kwargs)  # type: ignore
  File "C:\Users\bobot\AppData\Local\Programs\Python\Python311\Lib\site-packages\discord\ext\commands\core.py", line 235, in wrapped
    ret = await coro(*args, **kwargs)
  File "C:\Users\bobot\OneDrive\Documents\projs\py\cool.py", line 48, in setup
    msg = input("Message to send: ")

我推测是input()阻塞了Discord Bot的事件循环,求解决方法。

解决方法

你的推测完全正确,input()是同步阻塞函数,会卡住asyncio的事件循环,导致Bot无法处理其他事件(比如接收消息、心跳包)。下面给两种可行的修复方案:

方案一:用asyncio.run_in_executor异步获取输入

把同步的input()放到线程池里执行,不阻塞事件循环,同时记得给ctx.send()加上await(原代码里漏了,会导致消息发不出去):

import discord
import asyncio
from discord.ext import commands
from concurrent.futures import ThreadPoolExecutor

intents = discord.Intents.all()
bot = commands.Bot(command_prefix="!", intents=intents)
# 创建线程池,用来处理同步输入
executor = ThreadPoolExecutor(max_workers=1)

@bot.event
async def on_ready():
    print("Logged in as {}".format(bot.user))

def get_input(prompt):
    return input(prompt)

@bot.command()
async def setup(ctx):
    await ctx.message.delete()
    while True:
        # 在线程池里执行input,不阻塞事件循环
        msg = await bot.loop.run_in_executor(executor, get_input, "Message to send: ")
        # 发送消息必须加await
        await ctx.send(msg)

方案二:单独开线程处理控制台输入

另一种方式是启动一个独立线程专门监听控制台输入,这样事件循环和输入处理互不干扰:

import discord
import threading
from discord.ext import commands

intents = discord.Intents.all()
bot = commands.Bot(command_prefix="!", intents=intents)
# 保存目标频道对象,用于线程里发送消息
target_channel = None

@bot.event
async def on_ready():
    print("Logged in as {}".format(bot.user))

def console_input_loop():
    global target_channel
    while True:
        msg = input("Message to send: ")
        if target_channel:
            # 用bot.loop.create_task把同步线程里的操作放到事件循环执行
            bot.loop.create_task(target_channel.send(msg))

@bot.command()
async def setup(ctx):
    global target_channel
    await ctx.message.delete()
    target_channel = ctx.channel
    print("Now you can send messages via console!")

注意启动Bot前要先启动输入线程:

# 在bot.run前添加
threading.Thread(target=console_input_loop, daemon=True).start()
bot.run("YOUR_TOKEN_HERE")

额外注意点

  • 原代码里ctx.send(msg)没有加await,这是错误的,必须用await才能正确发送消息。
  • 如果要退出输入循环,可以加个终止条件,比如输入exit时break:
    msg = await bot.loop.run_in_executor(executor, get_input, "Message to send (type 'exit' to quit): ")
    if msg.lower() == "exit":
        print("Exiting input mode.")
        break
    

内容的提问来源于stack exchange,提问作者Xenan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 00:01:00