【问题标题】:Why is this iteration so slow?为什么这个迭代这么慢?
【发布时间】:2021-11-29 17:48:11
【问题描述】:

我似乎无法理解为什么这个迭代如此缓慢,所以我希望有人能帮助我。 此功能用于在特定时间安排一些操作,并循环机器人列表(将执行操作)和组列表(操作的目标) 完成 1300 个组和 50 个机器人大约需要 10 分钟。提前谢谢您,这非常重要!

for (let groupIndex = 0; groupIndex < groups.length; groupIndex++) {
    let group = groups[groupIndex];

    if (!answers.find(a => a.GroupId == group.Id))
        continue;

    for (let botIndex = 0; botIndex < bots.length; botIndex++) {
        var bot = bots[botIndex];
        if (bot.Disabled)
            continue;

        var bot_joined_groups = bots_joined_groups.find(j => j.Id == bot.Id);
        if (bot_joined_groups) {
            bot_joined_groups = bot_joined_groups.Groups;
            if (bot_joined_groups.find(j => j.GroupId == group.Id))
                continue;
        } else
            bot_joined_groups = [];

        var day = 60 * 60 * 24 * 1000;

        var today = new Date();
        if (today < (new Date(bot.WarmingUpEndAt)))
            today = new Date(bot.WarmingUpEndAt);
        else if (Math.floor((Date.parse(today) - Date.parse(bot.LimitAt)) / 86400000) < 7) {
            today = new Date(bot.LimitAt);
            today.setTime(today.getTime() + day * 7);
        }

        var scheduled_joins = scheduled_joins_total.filter(j => j.BotId == bot.Id);

        var schedule_date = new Date();

        if (scheduled_joins.length) {
            schedule_date = scheduled_joins.find(j => {
                let at = new Date(j.At);
                let count = scheduled_joins.filter(c => at.getDate() === new Date(c.At).getDate() && at.getMonth() === new Date(c.At).getMonth() && at.getFullYear() === new Date(c.At).getFullYear()).length;

                if (count < 10)
                    return true;
            });

            if (schedule_date)
                schedule_date = new Date(schedule_date.At);
            else {
                schedule_date = new Date(scheduled_joins[scheduled_joins.length - 1].At);
                schedule_date = new Date(schedule_date.getTime() + day);
            }
        } else
            schedule_date = today;

        let min_hours = 0;
        let min_minutes = 0;

        if (today.getDate() == schedule_date.getDate() && today.getMonth() == schedule_date.getMonth() && today.getFullYear() == schedule_date.getFullYear()) {
            var joined_today_count = bot_joined_groups.filter(c => today.getDate() === new Date(c.JoinedAt).getDate() && today.getMonth() === new Date(c.JoinedAt).getMonth() && today.getFullYear() === new Date(c.JoinedAt).getFullYear()).length;

            if (joined_today_count >= 10) {
                schedule_date = new Date(scheduled_joins_total.length ? (new Date(scheduled_joins_total[scheduled_joins_total.length - 1].At)).getTime() : today.getTime() + day);
                min_hours = 0;
                min_minutes = 0;
            }
            else {
                if (today.getHours() == 23) {
                    schedule_date = new Date(scheduled_joins_total.length ? (new Date(scheduled_joins_total[scheduled_joins_total.length - 1].At)).getTime() : today.getTime() + day);
                    min_hours = 0;
                    min_minutes = 0;
                }
                else {
                    if (schedule_date.getHours() <= today.getHours())
                        min_hours = today.getHours() + 1;

                    joined_today_count++;
                }
            }
        }

        schedule_date.setHours(Math.random() * (23 - min_hours + 1) + min_hours);
        schedule_date.setMinutes(Math.random() * 59 + min_minutes);
        schedule_date.setSeconds(Math.random() * 59);

        var today_joins_count = 0;
        do {
            today_joins_count = scheduled_joins_total.filter(c => schedule_date.getDate() === new Date(c.At).getDate() && schedule_date.getMonth() === new Date(c.At).getMonth() && schedule_date.getFullYear() === new Date(c.At).getFullYear() && c.GroupId === group.Id).length;
            if (today_joins_count)
                schedule_date.setTime(schedule_date.getTime() + day);
        } while (today_joins_count);

        scheduled_joins_total.push({
            BotId: bot.Id,
            GroupId: group.Id,
            At: schedule_date
        });

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

【问题讨论】:

  • 真的,您应该使用计时器和 console.logging 基准来查找最慢的行,并研究替代方法。对于初学者,请查看nikitahl.com/how-to-find-an-item-in-a-javascript-array
  • 如果你可以使用对象或Map来查找id,而不是多次调用find,性能应该会大大提高。
  • 我建议更多的散列和更多的缓存。
  • 在每个循环中都会发生大量一次性声明。有很多改进的机会。

标签: javascript performance loops


【解决方案1】:

O(n^2)? 如果

!answers.find(a => a.GroupId == group.Id)

是一个与groups 长度相似的数组或列表,那么您可以期望每个迭代 在内存中查找1300 个项目,而不是进行大约1 次迭代工作。总的来说,在内存中查找值需要 1300 * 1300 次。

如 cmets 中所述,您可以改用哈希表或直接查找表。

如果您经常检索数据,基本上可以尝试以一种可以快速检索数据的方式存储数据。

在这种情况下,您可能需要一个关系数据库,或者如果您对暂时的数据不一致感到满意,您也可以将组成员存储在原始搜索中,这样您只需进行一次查找。

相关:https://stackoverflow.com/a/487278/7818349

【讨论】:

    猜你喜欢
    • 2021-04-29
    • 2018-07-22
    • 1970-01-01
    • 2017-01-10
    • 2011-08-31
    • 1970-01-01
    • 2018-01-20
    • 2011-05-07
    • 1970-01-01
    相关资源
    最近更新 更多