闭包捕获的 upvalue 存在函数原型(F:\底层文件 的 Proto 结构)关联的 UpValue 上,不占全局表、多个闭包实例各持独立副本。利用这一特性把计数器与时间窗封在闭包内部,就能给任意函数套上节流壳:窗口内超过限额的调用直接丢弃。攻城战 500 人同时拾取装备,每条拾取都 sendmsg 播报,单帧 500 次聊天接口调用;节流后每 100 毫秒窗口只放行 10 条,其余静默。
通用节流壳:计数器与窗口起点都是 upvalue,多业务各自实例化互不干扰。示例代码如下:
local function throttle(fn, maxCalls, windowMs)
local count = 0
local windowStart = 0
return function(...)
local now = os.clock() * 1000
if now - windowStart >= windowMs then
windowStart = now
count = 0
end
if count >= maxCalls then
return nil
end
count = count + 1
return fn(...)
end
end
给拾取播报套壳:100 毫秒窗口最多放行 10 条。示例代码如下:
local rawPickMsg = function(actorName, itemName)
sendmsg(nil, 1, actorName .. " 拾取了 " .. itemName)
end
local pickMsg = throttle(rawPickMsg, 10, 100)
500 人同时拾取时 rawPickMsg 被 500 次引用,pickMsg 只放行窗口内前 10 条,其余返回 nil 不打扰聊天频道。
同屏 500 人同时拾取的攻城场景:未节流时每帧 500 次 sendmsg,聊天接口累计耗时约 25 毫秒,消息刷屏导致玩家主动关闭聊天框;节流后每帧最多 10 次调用约 2.5 毫秒,耗时降到原来的1/10规模。节流壳自身开销:一次 os.clock 与两次比较约 0.001 毫秒,500 次调用累计 0.5 毫秒,远小于省下的接口耗时。
三个不适用场景:一是不可丢弃的消息,交易凭据、系统邮件、奖励到账通知被节流丢弃就是资损,节流只用于播报类可丢消息;二是需要保序的业务,窗口内丢弃会造成下游看到的消息序与实际序不一致;三是窗口边界敏感的计数场景,滑动窗口需求(任意 1 秒内不超 N 次)用固定窗口实现会漏判边界突发,需改环形队列记录时间戳。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
设计初衷 敌对帮会边境摩擦不断:小规模遭遇天天有,谁都不敢先收手(怕被当成软弱)——敌对没有制度化的降温通道。互不侵犯协定设…
设计初衷 帮会扩张靠熟人拉人:增长有天花板、新人质量参差、老人不愿带新——帮会规模长期停滞。募兵制设计:帮会发布募兵任务包(…
底层原理 科赫曲线:把一条线段三等分,中段替换为凸起的三角折线,对每段递归重复——每迭代一次线段数乘 4。递归结构极简:dr…
底层原理 取玩家配置缺字段时返回 nil,调用方到处判 nil——判空代码散落每个调用点。空对象模式:缺配置时返回一个有默认…
设计初衷 行会规矩全靠会长嘴说:违规没有标准、赏罚全凭心情——帮规形同虚设,成员不服管理。帮规条款设计:行会规则条文化——条…
业务场景 防务报警靠人肉喊话:入侵者来了只能靠肉眼发现再频道通知。哨戒信标封装:部署信标覆盖警戒区,区域内出现入侵者时信标联…