引擎的 Lua 脚本跑在协作式调度里:一段脚本能跑多久,取决于它自己何时返回。批量操作(扫 5000 只怪物掉落、建 200 条索引)超过单帧预算就卡全服。协程把长任务切成可暂停的片段:每次 yield 让出执行权回引擎主循环,下帧 resume 接着跑。看门狗(watchdog)在协程外部计时——协程内部死循环不会自己让出,外部时钟是唯一的裁判。
协程看门狗:超时自动终止,正常完成返回结果。示例代码如下:
local function runWithWatchdog(fn, timeoutSec)
local co = coroutine.create(fn)
local startAt = os.time()
local result = nil
while coroutine.status(co) ~= "dead" do
if os.time() - startAt > timeoutSec then
sendmsg(nil, 1, "任务超时 " .. timeoutSec .. " 秒,已终止。")
return false, nil
end
local ok, val = coroutine.resume(co)
if not ok then
sendmsg(nil, 1, "协程异常:" .. tostring(val))
return false, nil
end
result = val
end
return true, result
end
批量任务接入:扫 2000 条掉落记录,每 200 条 yield 一次让出控制权。示例代码如下:
local function batchScan(actor)
actor = getplayerbyname(actor)
local co = coroutine.create(function()
local count = 0
for i = 1, 2000 do
count = count + 1
if count % 200 == 0 then
coroutine.yield(count)
end
end
sendmsg(actor, 1, "扫描完成:" .. count .. " 条。")
end)
local startAt = os.time()
while coroutine.status(co) ~= "dead" do
if os.time() - startAt > 5 then
sendmsg(actor, 1, "扫描超时终止。")
break
end
coroutine.resume(co)
end
end
本篇的新技术点是"外部时钟即裁判":协程内部死循环不会自己让出,看门狗用绝对时间戳在外部判定超时——这是协程安全运行的兜底保障。
同步执行与协程分帧对照:2000 条扫描同步跑耗时 480ms(卡帧明显),协程分帧后单帧 3.2ms——玩家无感知。看门狗开销:每次循环一次 os.time 减法加比较,千次循环多 0.2ms。批量任务从"可能卡全服"变成"分帧无感"的体验差异是核心价值,纯耗时差异可忽略。
看门狗适合耗时不可预估的批量操作(扫描条数取决于数据量);耗时确定且短暂(毫秒级)的操作不需要看门狗。另外,协程内部不能有不可中断的原子操作(如扣款加发货),中间被看门狗终止会导致半完成状态——这类操作要么拆成独立小步要么改用事务机制。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
设计初衷 背包无限装:药水带一百瓶、材料囤到爆——负重没有成本,背包管理沦为无脑囤积。负重系统设计:每件物品带重量,总负重超…
设计初衷 装备栏有武器位没有副手位:副手要么没用、要么变成第二武器直接双倍攻击——副手的定位从来没人讲清。副手装备设计:主手…
底层原理 对不同类型的节点执行不同操作(战绩流水里的击杀、阵亡、助攻各有统计口径),把操作散在类型判断里,每加一种操作就要改…
底层原理 行会的战力由成员战力组成、成员战力由装备组成——"整体"与"部分"要能用同一个接口对待:问行会战力与问成员战力是同…
设计初衷 输出成长只有堆攻击一条路:攻击加成稀释严重(基础 2000 再加 200 体感无几),成长反馈越来越钝。增伤属性设…
业务场景 驻地守御靠玩家人肉站桩:离线时段防务真空。箭塔守御封装:驻地点位部署箭塔(帮会资金建造),箭塔自动索敌(优先最近、…