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。不同战力成员都有参与感。 策划要点与配置 …
实战应用:用在哪里 副本限时挑战加入超时血量惩罚:超时后BOSS攻击递增。上线后BOSS攻击叠到十倍秒杀全队。 事故还原与补…
实战应用:用在哪里 混沌麒麟召唤是全服高光时刻:暗幕聚合、裂缝展开、麒麟着陆三段演出各1.3秒。 三段式入场演出编排 围观镜…
实战应用:用在哪里 任务对话一闪而过玩家想回顾。回看接口把对话按节点存档,面板翻阅全部对话记录。 对话存档与查询渲染 当前章…
实战应用:用在哪里 服务器承载六十张地图,空闲地图白耗资源。按需激活,末人离开后六十秒休眠。 激活与休眠触发 休眠回收 验证…
实战应用:用在哪里 坐骑资质洗炼随机重滚五条属性,锁定满意的条目不再重滚,锁定越多消耗越大。 洗炼与锁定 锁定消耗递增 验证…