CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
性能调优循环优化

【性能调优】循环内查询外提:重复查找的缓存消除

2026-09-23 17:01 作者:996 技术组 996引擎Lua教程传奇脚本

实战应用:用在哪里

循环里的每一步都在做同样的查找:配置表按名字反复索引、引擎变量反复读取、同一个函数反复调用——结果不变的计算被重复执行。查询外提把循环内不变的计算搬到循环外做一次,省下的是整个循环的重复量。

外提的现场

lua
---改造前:循环内反复查配置与读变量
function Loop.bad(actor, monList)
    for _, mon in ipairs(monList) do
        local cfg = getplayvar(actor, 2, "DropCfg")    -- 每次读
        local rate = cfg[mon].rate                     -- 每次索引
        if math.random(1, 10000) <= rate then
            Drop.give(actor, mon)
        end
    end
end

---改造后:不变项外提一次
function Loop.good(actor, monList)
    local cfg = getplayvar(actor, 2, "DropCfg")        -- 提到循环外
    for _, mon in ipairs(monList) do
        local rate = cfg[mon].rate
        if math.random(1, 10000) <= rate then
            Drop.give(actor, mon)
        end
    end
end

外提的判断标准一句话:循环体内不变的表达式搬到循环外。getplayvar 的读取在循环里结果恒定——它是外提的教科书案例:读一次存进局部变量,循环内直接用局部值,万次循环省下万次引擎调用。外提的收益实测:千只怪的掉落循环从 42 毫秒降到 9 毫秒,五倍的差距全部来自把不变量搬出循环。

外提的边界

lua
---不变性成立的三个条件
function Loop.safeHoist(actor, monList)
    -- 条件一:被提的值在循环内不被修改
    local cfg = getplayvar(actor, 2, "DropCfg")
    -- 条件二:被提的调用无副作用
    local total = #monList
    -- 条件三:依赖的外部状态循环内恒定
    for i, mon in ipairs(monList) do
        if i <= total then
            local rate = cfg[mon].rate
            if math.random(1, 10000) <= rate then
                Drop.give(actor, mon)
            end
        end
    end
end

外提的边界三条:被提的值在循环内确实不变(循环体里改了它就不能提)、被提的调用无副作用(有副作用的调用挪动会改变行为)、依赖的外部状态循环内恒定(引擎状态被循环内的操作改变时不可提)。三条有一条不满足,外提就是把性能 Bug 换成逻辑 Bug——改写前的语义确认比改写本身重要。混合的形态:部分不变部分变化的外层结构不变、内层变化的字段照读,逐字段的判断比整表的外提更细。

验证与监控

改造前后的行为等价测试:同输入的输出逐值比对,外提不能改变任何可见行为;循环的耗时基准改造前后对比,收益不达 20% 的改造回退。

踩坑记录

外提曾经把会变的引擎状态一起提出来,循环内状态的变更读不到旧值,不变性的复核加严。局部缓存的变量曾经在循环内被间接修改(通过引用的表),缓存的失效时机漏判,快照与失效的配套补上。优化的热度曾经驱动全量外提,冷路径的外提让代码可读性崩坏,外提只做热点。

上线要点

外提的规范进评审清单:循环内不变的查询必须外提。热点循环的耗时进性能的周报,回归的循环自动进改造候选。等价测试的模板进公共库,外提的改造永远带着测试走。

作者履历与出处

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

← 返回文章地图返回研学路径

最新技术文章 · 实战干货

LATEST ARTICLES

全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

策划架构996引擎数值模型裁决之杖强化

【策划架构】裁决之杖强化:成功率曲线与保护阈值的数值模型

设计初衷 强化是装备养成的主消耗口:黑铁矿石、金币、幸运后续材料都从这里回收。数值目标三条:前期强化爽感足(+1 到 +3 …

2026-09-24 05:19 996 技术组
策划架构996引擎数值模型沙巴克经济系统

【策划架构】沙巴克经济:城主税收与拍卖分成的数值模型

设计初衷 沙巴克是全服经济的枢纽:占领它要有真金白银的回报,但回报过丰会让大行会永久垄断、新区行会干脆躺平。数值目标三条:城…

2026-09-24 05:19 996 技术组
策划架构996引擎数值模型红名惩罚设计

【策划架构】红名惩罚:爆装概率与洗名成本的数值设计

设计初衷 红名系统要同时吓住恶意PK、又不扼杀正常摩擦:惩罚过轻,恶人会蹲新手村门口屠杀;惩罚过重,行会战误伤没人敢动手。数…

2026-09-24 05:19 996 技术组
高级技巧996引擎Lua元表配置表

【高级技巧】兑换表只读保护:元表__newindex写拦截

底层原理 Lua 的写入规则:给表中一个不存在的键赋值时,引擎先查元表的 __newindex;__newindex 若是函…

2026-09-24 05:19 996 技术组
高级技巧996引擎Lua协程祖玛阁

【高级技巧】祖玛阁补怪:长任务的协程分帧与看门狗

底层原理 引擎的 Lua 脚本跑在协作式调度里:一段脚本能跑多久,取决于它自己何时返回。祖玛阁开门要补 2000 只祖玛卫士…

2026-09-24 05:19 996 技术组
高级技巧996引擎Lua性能沙巴克

【高级技巧】沙巴克战报广播:字符串拼接的GC压力治理

底层原理 Lua 字符串不可变:每次 .. 都新建一个字符串对象,旧的变成垃圾。沙巴克战报高峰,200 名参战玩家每秒产生约…

2026-09-24 05:19 996 技术组