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

discord.py机器人等待input()时心跳阻塞问题求助

问题根源

你这问题本质是同步的input()函数彻底阻塞了asyncio事件循环。Discord.py靠asyncio的事件循环维持和Discord网关的心跳连接,当input()卡在那等你输入时,事件循环根本没法处理心跳包,超过10秒就触发网关断开警告,机器人直接离线。

解决办法

办法1:用异步方式处理输入(适合本地调试)

把input()丢到单独线程里执行,不让它卡住事件循环,用asyncio.to_thread()就能实现:

import os
import discord
import asyncio

MyDiscordID = os.environ["DiscordID"]
people = os.environ["people"]
message = os.environ["message"]
client = discord.Client(intents=discord.Intents.all())
names = [people, "yourself"]

@client.event
async def on_ready():
    print(f"已登录:{client.user}")
    while True:
        # 把input放到线程里,不阻塞事件循环
        user_input = await asyncio.to_thread(input, "要给哪个用户发DM? ")
        if user_input == "yourself":
            user = await client.fetch_user(MyDiscordID)
            await user.send("# ```(此消息由机器人发送)```")
            await user.send(message)
            print("已给自己发送DM")
        elif user_input not in names:
            print("找不到这个用户ID")

client.run(os.environ["Token"])

办法2:改用Discord命令触发(推荐Replit托管用这个)

Replit托管的机器人后台运行时,控制台输入体验很差,不如直接在Discord里加个命令来触发发DM,完全不用依赖控制台:

import os
import discord
from discord import app_commands

MyDiscordID = os.environ["DiscordID"]
people = os.environ["people"]
message = os.environ["message"]
client = discord.Client(intents=discord.Intents.all())
tree = app_commands.CommandTree(client)
# 允许使用命令的用户ID列表
allowed_users = [int(MyDiscordID), int(people)]

@client.event
async def on_ready():
    await tree.sync()
    print(f"已登录:{client.user}")

@tree.command(name="send_dm", description="给指定用户发送预设DM")
async def send_dm(interaction: discord.Interaction, user_id: str):
    # 只让指定用户用这个命令
    if interaction.user.id not in allowed_users:
        await interaction.response.send_message("你没权限用这个命令", ephemeral=True)
        return
    
    try:
        target_user = await client.fetch_user(int(user_id))
        await target_user.send("# ```(此消息由机器人发送)```")
        await target_user.send(message)
        await interaction.response.send_message(f"已成功给用户{user_id}发DM", ephemeral=True)
    except discord.NotFound:
        await interaction.response.send_message("找不到这个用户", ephemeral=True)
    except Exception as e:
        await interaction.response.send_message(f"发送失败:{str(e)}", ephemeral=True)

client.run(os.environ["Token"])

办法3:单独开线程处理控制台输入

非要保留控制台输入的话,就开个独立线程专门处理输入,然后把发DM的操作丢回事件循环执行:

import os
import discord
import threading
import asyncio

MyDiscordID = os.environ["DiscordID"]
people = os.environ["people"]
message = os.environ["message"]
client = discord.Client(intents=discord.Intents.all())
names = [people, "yourself"]

def input_handler():
    while True:
        user_input = input("要给哪个用户发DM? ")
        # 把异步任务调度到事件循环里执行
        asyncio.run_coroutine_threadsafe(send_dm(user_input), client.loop)

async def send_dm(user_input):
    if user_input == "yourself":
        user = await client.fetch_user(MyDiscordID)
        await user.send("# ```(此消息由机器人发送)```")
        await user.send(message)
        print("已给自己发送DM")
    elif user_input not in names:
        print("找不到这个用户ID")

@client.event
async def on_ready():
    print(f"已登录:{client.user}")
    # 启动输入线程,设为守护线程随主程序退出
    threading.Thread(target=input_handler, daemon=True).start()

client.run(os.environ["Token"])
注意点
  • Replit托管时,优先选办法2,控制台输入在后台环境下基本没法正常用。
  • 所有和Discord API交互的操作必须在asyncio事件循环里执行,不能在普通线程里直接调用异步方法,得用asyncio.run_coroutine_threadsafe或者loop.call_soon_threadsafe来调度。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 14:25:37