Lua 构建列表的两派写法:table.insert(t, v) 与 t[#t+1] = v。功能等价,性能的江湖传言却互相矛盾——有人说函数调用慢一截,有人说 5.1 之后没差别。拿数据说话,差别在哪、什么时候在意、什么时候根本不用在意。
---两种尾部插入的基准对比
local N = 3000000
local t0 = os.clock()
local a = {}
for i = 1, N do
table.insert(a, i)
end
local t1 = os.clock()
local b = {}
for i = 1, N do
b[#b + 1] = i
end
local t2 = os.clock()
print(string.format("insert: %.3fs hashlen: %.3fs", t1 - t0, t2 - t1))
300 万次插入的实测:table.insert 约 0.31 秒,#t+1 写法约 0.24 秒,后者快两成出头——差距来自函数调用的开销与 # 取长度的边界计算。两成听起来可观,但换算到业务:一场攻城战累计插入几万条伤害记录,两种写法的差异在微秒级,玩家无感。
---大列表的预分配构造
local N = 3000000
local c = {}
for i = 1, N do
c[i] = i -- 顺序赋值,解释器按数组段优化
end
---批量构建掉落列表的实测场景
function Drop.buildList(monName)
local out = {}
local tbl = DROP_TABLE[monName] or {}
for i, d in ipairs(tbl) do
out[i] = d.item -- 索引赋值优于尾部追加
end
return out
end
比尾部插入快一个档次的是顺序索引赋值:c[i] = i 的写法让 Lua 的数组段按整数键紧凑增长,省掉长度查询。掉落表的构建用 ipairs 遍历加索引赋值,列表越大收益越明显。结论的分层:热循环里百万级的插入选索引赋值;业务代码里百级别的追加两种写法任选,可读性优先;真正的性能瓶颈几乎从不在插入方式,先测再改是纪律。
基准脚本随版本库提交,引擎升级后重跑对比;战斗日志的构建耗时抽样,超过 5 毫秒的构建点回查数据结构选型。
基准曾经在一次跑完下结论,JIT 预热让首轮数据虚高,预热一万次后计时才稳定。#t 的长度曾经在含空洞的表上统计出错,中间删过元素的表长度不可预期,删除场景改用标记删除加压实。一段优化代码把可读的 insert 换成索引赋值,列表实际只有 8 个元素,优化的收益为零还引入了下标错位的 bug,优化的门槛以实测数据为准。
团队的性能规范写明分层:热路径用索引赋值,业务路径自由。代码评审对性能改动的第一问是基准数据在哪。构造型列表的容量可预估时用预填nil再填充的技巧,扩容次数减半。
本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
实战应用:用在哪里 排行榜卡死拖累登录、成就推送挤占带宽,这些非核心功能出问题时最需要的是一个总闸。服务降级预案定义了核心链…
实战应用:用在哪里 单件装备的属性提升有限,套装共鸣让多件装备产生化学反应:穿戴同系三件以上触发共鸣属性,五件触发全局光环。…
实战应用:用在哪里 同一账号在两台设备同时在线,一台打怪一台交易,是盗号者测试密码后的标准动作。多设备在线检测在登录环节检查…
实战应用:用在哪里 老服合并、机房迁移、数据分库改造,都涉及角色数据的批量搬家。数据迁移的核心是搬运过程中不断服、不丢数据、…
实战应用:用在哪里 沙影之路的暗之Boss是行会实力的试金石:真身与三个镜像随机分布在四个祭坛,只有击杀真身才有掉落,镜像被…
实战应用:用在哪里 攻城战最容易变成人海推门的无脑玩法。攻城拔寨将城门攻坚设计为三线战术:正面强攻吸引火力、侧翼工程车破城、…