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

1300个群组50个机器人的循环迭代运行耗时10分钟,请问性能缓慢原因是什么?

性能问题根因

你的代码核心问题是O(n²)甚至更高的时间复杂度,1300个群组、50个机器人的场景下总共有65000次内外层循环迭代,每次迭代中反复执行find/filter这类O(n)操作,且随着scheduled_joins_total数组不断变长,后续遍历成本会越来越高,最终运行时间被指数级放大。

具体优化方案

1. 提前构建全局索引,将查找操作降为O(1)

所有需要反复查找的数据集,在循环开始前一次性处理成哈希结构:

  • 将answers中的GroupId存入Set,直接判断群组是否需要处理
  • 将bots_joined_groups处理为Map:key为botId,value为该bot已加入群组ID的Set,无需每次遍历查找
  • 将scheduled_joins_total预分组:按botId分组存储调度记录,同时构建日期+groupId的全局Set,用于快速判断某群组当天是否已有调度
  • 所有日期提前转为YYYYMMDD格式的字符串,避免反复调用getDate/getMonth/getFullYear做日期对比

2. 提取循环外的常量与重复计算

  • 把day = 86400000这类常量提到循环最外层,无需每次迭代重新计算
  • 全局统一计算当前日期,不要每次迭代都新建Date()对象
  • 提前过滤掉禁用的bot,减少内层循环次数

3. 优化调度计数逻辑

提前统计每个bot每日的调度次数,不要每次查找时遍历全部调度记录计算


优化后代码示例
// 提前预处理所有索引
const ANSWER_GROUP_SET = new Set(answers.map(a => a.GroupId));
const BOT_JOINED_GROUP_MAP = new Map(
  bots_joined_groups.map(j => [j.Id, new Set(j.Groups.map(g => g.GroupId))])
);
// 预分组bot调度记录,同时构建日期-group的索引
const BOT_SCHEDULE_MAP = new Map();
const DATE_GROUP_SET = new Set();
const day = 86400000;
const now = new Date();
const getDateStr = (d) => `${d.getFullYear()}${String(d.getMonth()+1).padStart(2,'0')}${String(d.getDate()).padStart(2,'0')}`;

// 初始化调度数据索引
scheduled_joins_total.forEach(item => {
  const dateStr = getDateStr(new Date(item.At));
  if (!BOT_SCHEDULE_MAP.has(item.BotId)) {
    BOT_SCHEDULE_MAP.set(item.BotId, {
      records: [],
      dayCount: new Map()
    });
  }
  const botData = BOT_SCHEDULE_MAP.get(item.BotId);
  botData.records.push(item);
  botData.dayCount.set(dateStr, (botData.dayCount.get(dateStr) || 0) + 1);
  DATE_GROUP_SET.add(`${dateStr}_${item.GroupId}`);
});

// 提前过滤可用bot
const availableBots = bots.filter(b => !b.Disabled);

for (const group of groups) {
  // O(1)判断群组是否需要处理
  if (!ANSWER_GROUP_SET.has(group.Id)) continue;
  
  for (const bot of availableBots) {
    // O(1)判断bot是否已加入该群
    const joinedGroups = BOT_JOINED_GROUP_MAP.get(bot.Id) || new Set();
    if (joinedGroups.has(group.Id)) continue;

    // 计算基准日期
    let today = new Date(now);
    const warmEnd = new Date(bot.WarmingUpEndAt);
    if (today < warmEnd) {
      today = warmEnd;
    } else {
      const limitAt = new Date(bot.LimitAt);
      if (Math.floor((today.getTime() - limitAt.getTime()) / day) < 7) {
        today = new Date(limitAt.getTime() + 7 * day);
      }
    }
    const todayStr = getDateStr(today);

    // 计算调度起始日期
    let scheduleDate = new Date(today);
    const botSchedule = BOT_SCHEDULE_MAP.get(bot.Id) || {records: [], dayCount: new Map()};
    if (botSchedule.records.length) {
      // 直接从预统计的日计数里找符合要求的日期
      let foundDate = null;
      for (const [dateStr, count] of botSchedule.dayCount.entries()) {
        if (count < 10) {
          foundDate = new Date(dateStr.slice(0,4), parseInt(dateStr.slice(4,6))-1, parseInt(dateStr.slice(6,8)));
          break;
        }
      }
      if (foundDate) {
        scheduleDate = foundDate;
      } else {
        // 取最后一条记录加一天
        const lastRecord = botSchedule.records[botSchedule.records.length-1];
        scheduleDate = new Date(new Date(lastRecord.At).getTime() + day);
      }
    }
    const scheduleDateStr = getDateStr(scheduleDate);

    // 计算最小时分
    let minHours = 0, minMinutes = 0;
    if (todayStr === scheduleDateStr) {
      // 统计当天已加入数量
      let joinedTodayCount = 0;
      const joinedGroups = BOT_JOINED_GROUP_MAP.get(bot.Id) || [];
      for (const g of joinedGroups) {
        if (getDateStr(new Date(g.JoinedAt)) === todayStr) joinedTodayCount++;
      }
      if (joinedTodayCount >= 10 || today.getHours() >= 23) {
        // 跳到下一天
        if (scheduled_joins_total.length) {
          const lastGlobal = scheduled_joins_total[scheduled_joins_total.length-1];
          scheduleDate = new Date(new Date(lastGlobal.At).getTime() + day);
        } else {
          scheduleDate = new Date(today.getTime() + day);
        }
        minHours = 0;
        minMinutes = 0;
      } else {
        if (scheduleDate.getHours() <= today.getHours()) {
          minHours = today.getHours() + 1;
        }
      }
    }

    // 随机时间
    scheduleDate.setHours(Math.random() * (23 - minHours + 1) + minHours);
    scheduleDate.setMinutes(Math.random() * 59 + minMinutes);
    scheduleDate.setSeconds(Math.random() * 59);

    // O(1)判断该日期+群组是否已有调度
    let finalDateStr = getDateStr(scheduleDate);
    while (DATE_GROUP_SET.has(`${finalDateStr}_${group.Id}`)) {
      scheduleDate.setTime(scheduleDate.getTime() + day);
      finalDateStr = getDateStr(scheduleDate);
    }

    // 更新索引与结果
    const scheduleItem = {
      BotId: bot.Id,
      GroupId: group.Id,
      At: scheduleDate
    };
    scheduled_joins_total.push(scheduleItem);
    // 更新bot调度索引
    if (!BOT_SCHEDULE_MAP.has(bot.Id)) {
      BOT_SCHEDULE_MAP.set(bot.Id, {records: [], dayCount: new Map()});
    }
    const botData = BOT_SCHEDULE_MAP.get(bot.Id);
    botData.records.push(scheduleItem);
    botData.dayCount.set(finalDateStr, (botData.dayCount.get(finalDateStr) || 0) + 1);
    DATE_GROUP_SET.add(`${finalDateStr}_${group.Id}`);

    values.push(`(${bot.Id}, ${group.Id}, to_timestamp(${scheduleDate.getTime() / 1000.0}))`);
  }
}

优化后整体运行时间可降到秒级。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 22:45:02