在Lua中热插拔代码。
2012-2-20 22:21:6
收藏:0
阅读:144
评论:2
我在网络上听到过一些关于能够类似于 Java、Erlang、Lisp 等语言中那样在 Lua 中进行热插拔编码的议论。然而,我花了 30 分钟在 Google 上搜索,却没有发现任何有意义的信息。有人读到过相关的实质性内容吗?有人有这方面的经验吗?这个技术只在 LuaJIT 上可行还是只在参考虚拟机中可行?
我更感兴趣的是这个技巧在开发/调试中的快捷方式,而不是在实际环境中的升级路径。
原文链接 https://stackoverflow.com/questions/9369318
点赞
stackoverflow用户668125
正如 Nicol 所说,语言本身并不能为你做到这一点。
如果你想要自己实现这样的功能,那么并不太难,唯一的障碍是任何“剩余”的引用(它们仍将指向旧代码)以及 require
将其返回值缓存在 package.loaded
中的事实。
我会将你的代码分为 3 个模块:
- 入口点的重载逻辑(
main.lua
) - 你想要在重载之间保留的任何数据(
data.lua
) - 实际的重载代码(
payload.lua
),确保你不会保留任何对它的引用(有时当你需要把回调传递给某些库时可能不可能;见下文)。
-- main.lua:
local PL = require("payload")
local D = require("data")
function reload(module)
package.loaded[module]=nil --这让 `require` 忘记了它的缓存
return require(module)
end
PL.setX(5)
PL.setY(10)
PL.printX()
PL.printY()
-- .... 某种方式检测到你想要重载:
print "reloading"
PL = reload("payload") -- 确保你不会在其他地方保留对 PL 的引用,例如函数 upvalue!
PL.printX()
PL.printY()
-- data.lua:
return {} -- 这是一个相当愚蠢的模块,它只是一个在 `package.loaded.data` 中存储的表,确保每个人在需要时都能获得相同的实例。
-- payload.lua:
local D = require("data")
local y = 0
return {
setX = function(nx) D.x = nx end, -- 使用 data 模块被保留
setY = function(ny) y = ny end, -- 使用本地将在重载时重置
printX = function() print("x:",D.x) end,
printY = function() print("y:", y) end
}
输出:
x:5
y:10
reloading
x:5
y:0
你可以更好地完善那个逻辑,通过一个 "注册表模块" 为你跟踪所有需要/重载的模块,并将模块的所有访问抽象出来(从而使你可以替换引用),并且使用该注册表上的 __index
元表,你可以使其几乎透明,而无需在各个地方都调用丑陋的 getter。这也意味着,如果第三方库需要,你可以提供“一行代码的”回调,然后实际上只是通过注册表进行尾调用。
2019-08-15 11:46:28
评论区的留言会收到邮件通知哦~
推荐文章
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
Lua,以及大多数脚本语言,不支持您定义的最通用的“热交换”形式。也就是说,您不能保证更改磁盘上的文件,并使其中的任何更改传播到正在执行的程序中。
但是,Lua以及大多数脚本语言都可以进行可控制的热交换形式。全局函数是全局函数。如果您以这种方式使用它们,模块只需加载全局函数即可。因此,如果模块加载全局函数,则可以再次重新加载模块(如果它已更改),并且这些全局函数引用将更改为新加载的函数。
但是,Lua以及大多数脚本语言对此没有任何保证。所有的都是全局状态数据的更改。如果有人将旧的函数复制到了本地变量中,则仍然可以访问它。如果您的模块使用本地状态数据,新版本的模块将无法访问旧模块的状态。如果模块创建某种具有成员函数的对象,除非从全局获取这些成员,否则这些对象将始终引用旧函数,而不是新函数。等等。
此外,Lua不是线程安全的;您不能只中断某个点上的`lua_State'并尝试重新加载模块。因此,您必须设置某些时间点来检查并重新加载更改的文件。
因此,您可以这样做,但在某种意义上它并不“得到支持”。您必须为此付出努力,并小心编写内容以及全局和本地函数的放置。