如何在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循环,同时保持机器人在线。 - 输入验证:增加频道权限和任务状态判断,避免重复启动或无效操作。
关于数小时后自动停止的额外建议:
- 确保
keep_alive脚本正常工作,它会定期发送请求维持主机连接不被重置。 - 不要把Ping间隔设得太短,Discord有消息频率限制,频繁发送可能导致机器人被临时限制甚至封号。
- 可在代码中添加异常捕获,比如捕获发送消息时的网络异常,避免单个错误导致整个任务崩溃。
内容的提问来源于stack exchange,提问作者againzeenox
相关产品推荐
相关产品推荐

