我们知道,lua通过package模块来管理模块的搜索和加载,当利用require初次成功加载一个模块后,模块(Table)会被存储在package.loaded中,之后的require行为会直接获取到已加载的模块缓存。
怎样在步伐执行时,将对模块文件的修改热更新到步伐中,同时确保运行时状态的正常。这是项目开辟中常见的机制需求,这里给出一个遍历模块键值更换更新的方案:将新文件利用loadfile加载进内存,遍历原Table,根据key匹配value进行更换更新。
方案需要支持对运行时状态数据的继续。
模块在内存中以Table类型存在,我们把更新前的模块称为mod,在内存中的Table称为old_t,把新加载进内存的Table称为new_t。old_t被package管理:- registry.package = {
- loaded = {
- mod = old_t
- -- ...
- }
- }
复制代码 将修改后的模块文件利用loadfile加载进内存(没有内置的缓存机制,每次编译),遍历将old_t的键值更换为new_t,实现模块的更新:- -- load module file
- local new_t
- if package.loaded[mod] then
- local filename = package.searchpath(mod, package.path)
- local f, err = loadfile(filename)
- if not f then
- assert(false, string.format("loadfile err=%s", err))
- end
- new_t = f()
- end
- -- release old value
- local keys = table.allkeys(old_t)
- for _, k in ipairs(keys) do
- old_t[k] = nil
- end
- -- update new value
- for k, v in pairs(new_t) do
- old_t[k] = v
- end
复制代码 运行时状态数据的处理
我们可以约定:
- 需要继续的数据界说在模块的域内;
- 模块提供release方法用于处理并收集原Table中需要继续的内存数据;
- 模块提供onload方法用于将原Table的运行时数据继续到新的模块内存中
- local context, inherts
- local old_t = package.loaded[mod]
- if old_t and new_t then
- if old_t._release then
- context, inherts = old_t._release(old_t)
- end
- end
- -- inhert old_t runtime
- if context and inherts then
- for _, key in ipairs(inherts) do
- new_t[key] = old_t[key]
- end
- end
复制代码 给出一个符合上述热更新规范的模块设计demo:- local context = {} -- TODO logic agent context
- local logic = {
- _name = "logic",
- _inherit = { "_runtime" },
- _release = function(self)
- return context, self._inherit
- end,
- _onload = function(self, _context)
- print(string.format("run reload on mod %s", self._name))
- self._runtime._RELOAD_VERSION = self._runtime._RELOAD_VERSION + 1
- end,
- _runtime = {
- _RELOAD_VERSION = 1
- },
- _hotfixver = function(self)
- print("reload version:", self._runtime._RELOAD_VERSION)
- end
- }
- function logic.callfunc()
- print("run callfunc. [logic]")
- end
- return logic
复制代码 当我修改本地模块文件将callfunc函数界说为:- function logic.callfunc()
- print("run callfunc. [logic_v2]")
- end
复制代码 执行:- local logic = require "logic"
- local reload = require "reload"
- -- old_t
- logic.callfunc()
- reload("logic")
- -- new_t
- logic.callfunc()
- logic:_hotfixver()
复制代码 从输出效果可以看出,callfunc被正确更新为修改后的函数,切runtime数据被正确继续;- linxx@linxx-MacBookAir hotfix % lua tsreload.lua
- run callfunc. [logic]
- run reload on mod logic.
- run callfunc. [logic_v2]
- reload version: 2
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |