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

Discord.py结合AsyncIOScheduler出现心跳阻塞警告的问题求助

解决Discord.py机器人心跳阻塞警告问题

问题根源

你遇到的discord.gateway: Shard ID None heartbeat blocked for more than 10 seconds警告,本质是事件循环被长时间阻塞导致Discord网关的心跳包无法按时发送。你的read_site函数里存在多个同步阻塞操作:

  • 同步HTTP请求:requests.get是阻塞式的,网络请求过程中整个事件循环会卡住
  • 同步文件读写:open()/read()/write()都是同步操作,会占用事件循环
  • 网页解析:BeautifulSoup的HTML解析属于CPU密集型操作,同样会阻塞事件循环

这些操作单次执行可能耗时不长,但高频重复执行后,积累的负载会导致事件循环无法及时响应Discord的心跳检测,最终触发警告。misfire_grace_time仅用于处理任务错过调度的情况,无法解决事件循环阻塞的核心问题。

解决方案

将所有阻塞操作替换为异步实现,确保事件循环始终能及时处理Discord的心跳任务:

1. 安装必要的异步库

pip install aiohttp aiofiles

2. 修改代码为全异步实现

import os
import discord
import aiohttp
from bs4 import BeautifulSoup
import asyncio
from apscheduler.schedulers.asyncio import AsyncIOScheduler
import aiofiles

intents = discord.Intents.default()
intents.message_content = True
intents.members = True

client = discord.Client(intents=intents)

token = "token"

url = "site url"
params = {
    'id': 'id',
}
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
headers = {
    'User-Agent': user_agent
}

async def read_site():
    # 异步HTTP请求,不阻塞事件循环
    async with aiohttp.ClientSession() as session:
        async with session.get(url, params=params, headers=headers) as resp:
            content = await resp.read()
    
    # 将HTML解析放到线程池,避免CPU密集操作阻塞事件循环
    soup = await asyncio.to_thread(BeautifulSoup, content, 'html.parser')
    
    article_nums = soup.find("tbody").find_all("tr", class_="ub-content us-post")
    
    # 异步读取文件
    async with aiofiles.open("recent.txt", "r") as f:
        recent = int(await f.read())

    new_flag = False
    for val in article_nums:
        article_num = val.select_one("td", class_='num').get_text()
        if not article_num.isdecimal():
            continue
        article_num = int(article_num)
        
        if article_num > recent:
            new_flag = True
            recent = article_num

    if new_flag:
        channel = await client.fetch_channel(channel_id)
        await channel.send(str(recent))
        
    # 异步写入文件
    async with aiofiles.open("recent.txt", "w") as f:
        await f.write(str(recent))

@client.event
async def on_ready():
    await client.wait_until_ready()

    scheduler = AsyncIOScheduler()
    # 调整为你需求的10秒间隔,降低事件循环负载
    scheduler.add_job(read_site, 'interval', seconds=10, misfire_grace_time=10)
    scheduler.start()

    print(f'We have logged in as {client.user}')

client.run(token)

关键修改点说明

  • 异步HTTP请求:用aiohttp替代requests,网络请求过程中事件循环可同时处理Discord心跳等其他任务
  • 异步文件IO:用aiofiles替代同步文件操作,避免阻塞事件循环
  • 线程池处理解析:用asyncio.to_thread将HTML解析操作放到单独线程,隔离CPU密集型操作对事件循环的影响
  • 调整调度间隔:将原3秒间隔改为你描述的10秒,减少事件循环的高频负载

额外建议

  • 给网络请求和文件操作添加超时处理,避免单个任务长时间占用资源
  • 如果目标社区网站提供API,优先使用API获取数据,比网页解析更高效且资源占用更少

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:40:33