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

如何在Discord.py中终止while循环实现停止Ping功能

解决方案

直接上修改后的代码,解决循环终止问题,同时优化连接稳定性:

import discord
import os
import asyncio
from keep_alive import keep_alive

client = discord.Client()
# 用字典跟踪每个频道的Ping状态,键是频道名,值是布尔值
active_pings = {}
roleid = os.environ["@PingersRoleID"]
CategoryID = os.environ["PingsCategoryID"]
PingChannels = [
    "ping1",
    "ping2",
    "ping3",
    "ping4",
    "ping5",
    "ping6",
    "ping7",
    "ping8",
    "ping9",
    "ping10",
]
PingBotToken = os.environ["PingBotToken"]


@client.event
async def on_ready():
    print("{0.user} has joined the chat".format(client))
    # 初始化所有允许的频道状态为False
    for channel_name in PingChannels:
        active_pings[channel_name] = False


@client.event
async def on_message(message):
    username = str(message.author).split('#')[0]
    user_message = str(message.content)
    channel = str(message.channel.name)
    print("{} sent {} in {}".format(username, user_message, channel))

    # 忽略机器人自己的消息,避免死循环
    if message.author == client.user:
        return

    if user_message.lower() == "!activatepings":
        if channel in PingChannels and not active_pings[channel]:
            active_pings[channel] = True
            await message.channel.send("Ping任务已启动")
            # 用异步任务运行Ping循环,不阻塞事件循环
            asyncio.create_task(run_ping_loop(message.channel))
        elif active_pings[channel]:
            await message.channel.send("当前频道已经在运行Ping任务")
        else:
            await message.channel.send("此频道不允许启动Ping任务")

    elif user_message.lower() == "!stoppings":
        if channel in PingChannels and active_pings[channel]:
            active_pings[channel] = False
            await message.channel.send("Ping任务已停止")
        elif not active_pings[channel]:
            await message.channel.send("当前频道没有运行Ping任务")
        else:
            await message.channel.send("此频道不允许操作Ping任务")


async def run_ping_loop(channel):
    channel_name = channel.name
    while active_pings[channel_name]:
        await channel.send(f"<@&{roleid}>")
        # 控制Ping间隔,避免被Discord限流,这里设为10秒,可自行调整
        await asyncio.sleep(10)
    # 循环结束后重置状态(可选)
    active_pings[channel_name] = False


keep_alive()
client.run(PingBotToken)

关键改动说明:

  • 全局状态跟踪:用active_pings字典记录每个允许的频道是否在运行Ping任务,停止命令可直接修改状态终止循环。
  • 异步任务分离:把Ping循环放到单独的run_ping_loop函数,用asyncio.create_task启动,避免阻塞Discord事件循环——原代码的while True会卡死消息事件,导致机器人无法响应命令,甚至因长时间无心跳被Discord断开连接(这是数小时后停止的核心原因之一)。
  • 添加循环间隔:await asyncio.sleep(10)控制Ping频率,既避免刷屏过快被限流封号,也给事件循环留出时间处理心跳和其他命令。
  • 新增停止命令:!stoppings可终止对应频道的Ping循环,同时保持机器人在线。
  • 输入验证:增加频道权限和任务状态判断,避免重复启动或无效操作。

关于数小时后自动停止的额外建议:

  1. 确保keep_alive脚本正常工作,它会定期发送请求维持主机连接不被重置。
  2. 不要把Ping间隔设得太短,Discord有消息频率限制,频繁发送可能导致机器人被临时限制甚至封号。
  3. 可在代码中添加异常捕获,比如捕获发送消息时的网络异常,避免单个错误导致整个任务崩溃。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 04:36:12