网站建立前期调查,杭州公司摇号需要哪些资格条件,杭州做营销型网站,品牌型网站建设解决方案Hive是一个简单的LUA沙盒#xff0c;除了基本的LUA解释器的功能以外#xff0c;还提供了诸如热加载等功能。 了解HIVE的工作原理有利于了解Lua虚拟机的底层实现机理。 本文从是什么-怎么用-为什么三个维度介绍HIVE。
Hive
Hive是什么
hive是一个简单的LUA应用框架,目前基于…Hive是一个简单的LUA沙盒除了基本的LUA解释器的功能以外还提供了诸如热加载等功能。 了解HIVE的工作原理有利于了解Lua虚拟机的底层实现机理。 本文从是什么-怎么用-为什么三个维度介绍HIVE。
Hive
Hive是什么
hive是一个简单的LUA应用框架,目前基于LUA 5.3.4。
主要提供了文件沙盒,文件热加载以及一些基础的服务程序底层支持.
HIVE源码hive - master - gems / hive-framework - 工蜂内网版 (woa.com)
Hive的使用
编译 编译luna # at the hive-framework root directorycd luna makecp luan.so ../hive/编译hive # at the hive-framework root directorycd hive make运行
作为启动器的Hive
Hive本身只提供基础的热加载功能并没有太多的功能。
你可以把Hive看作是一个简单的lua启动器正如你使用lua file_name.lua一样你也可以使用如下的命令行启动你的lua代码—— # make sure the lua binary is under your PATHhive file_name.lua# just like lua file_name.lua!命令行参数
你也可以传递一些命令行参数进去这些命令行参数会被打包放进一个表里然后传递给你的脚本文件。
你可以使用hive.args在file_name.lua中来获取这些参数。 # ok,you can obtainhive file_name.lua arg1 arg2 arg3例如在你自己的业务代码里你可以写这样的代码 -- print the args-- test.luafor k,v in ipairs(hive.args) doprint(string.format(%d:%s\n,k,v))end保存为test.lua然后在命令行中使用 hive test.lua arg1 arg2 arg31:arg12:arg23:arg3业务代码 被Hive启动的Lua的业务代码中至少应该提供一个hive.run的实现—— --test.luahive.run function()print(Hello world)Hive.run会被反复执行效果如下所示—— hive test.luahello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello worldhello world...除此以外Hive还提供了一些feature这些feature可以在Lua的环境中用即在你自己的业务代码中使用。
Hive的特性
本章从使用的角度介绍Hive的特性如果需要详细了解实现原理欢迎参阅源码剖析和Hive接口手册章节。
文件热加载
所谓文件热加载是指但凡使用import函数引入的文件包括入口的文件例如上面的test.lua都会被Hive检测是否有更新。当Hive检测到文件时间戳改变以后会自动重新进行读取。
请观察下面的示例—— -- test.lual import(lobby.lua)hive.run function() print(in test.lua)print(the imported l is:,l.str)hive.sleep_ms(2000);end其中lobby.lua是另外一个lua程序 -- lobby.luastr Yes, I am a lobby输入hive test.lua运行 hive test.luathe imported l is: Yes, I am a lobbyin test.luathe imported l is: Yes, I am a lobbyin test.luathe imported l is: Yes, I am a lobbyin test.lua...在另外一个终端打开并修改lobby.lua文件保存 --lobby.luastr No!I am not a lobby!原终端中的输出发生改变 the imported l is: No, I am not a lobby!in test.luathe imported l is: No, I am not a lobby!in test.luathe imported l is: No, I am not a lobby!沙盒环境
使用import导入的文件Hive会为之创建了一个沙盒环境这使得各个文件中的变量名不会冲突。
下面的例子说明了import函数的行为—— -- lobby.luafunction m_add(a,b)return a bend function m_sub(a,b)return a - bendreturn 1123在test.lua中引入该文件 l import(lobby.lua)print(type(l))for k,v in pairs(l) doprint(k,:,v)end-- for k,v in pairs(_G) do-- print(k,:,v)-- endprint(l.m_add(1,2))print(l.m_sub(1000,2))得到结果如下所示可见之前的定义都放在一个表中且返回值被忽略了。 tablem_add : function: 0x228faa0m_sub : function: 0x229be803998如果使用require则有所不同 require(lobby)1123 v require(lobby) m_addfunction: 0xa5c340 m_subfunction: 0xa5c010有何不同 如果使用自带的require函数这里会有两个区别。 你可以获取到require的返回值全局的作用域被影响即这里的_G 本章节不涉及原理部分的阐述如有需要请参阅Hive接口手册。
源码剖析
热加载实现原理
这个主要和Hive::run代码有关 ...if(!lua_call_object_function(L, err, this, import, std::tie(), filename))die(err);while (lua_get_object_function(L, this, run)) {if(!lua_call_function(L, err, 0, 0))die(err);int64_t now ::get_time_ms();if (m_reload_time 0 now last_check m_reload_time) {lua_call_object_function(L, nullptr, this, reload);last_check now;}lua_settop(L, top);}lua_close(L);}首先将用户的代码#2使用import函数进行加载。如果没有错则继续进入一个循环。这个import函数是Hive提前定义好的一个函数。后面还会介绍。循环#5不断地从Lua环境中获取到Run函数的地址然后去调用如果获取不到函数地址则循环直接中止执行完毕。否则则直接进行调用获取到的Run函数。执行完毕以后检查import的文件是否有更新如果有则调用reload函数重新进行加载。
因此我们可以说如果业务代码中没有定义RUN函数则系统会直接返回。
沙盒环境实现原理
所谓沙盒环境其实就是不管怎么加载代码都用一个table给装起来而不污染全局的环境详情可见上面的特性章节。
沙盒的实现原理主要和Hive提前定义的load函数有关。 static const char* g_sandbox u8R__(hive.files {};hive.meta {__indexfunction(t, k) return _G[k]; end};hive.print function(...) end; --do nothinglocal get_filenode function(filename)local rootpath os.getenv(LUA_ROOT);local withroot rootpath and hive.get_full_path(rootpath)../..filename or filename;local fullpath hive.get_full_path(withroot) or withroot;local node hive.files[fullpath];if node thenreturn node;endlocal env {};setmetatable(env, hive.meta);node {envenv, fullpathfullpath, filenamefilename};hive.files[fullpath] node;return node;endfunction import(filename)local node get_filenode(filename);if not node.time thennode.time hive.get_file_time(node.fullpath);try_load(node);endreturn node.env;endhive.reload function()local now os.time();local update true;while update doupdate false;for path, node in pairs(hive.files) dolocal filetime hive.get_file_time(node.fullpath);if filetime ~ node.time and filetime ~ 0 and math.abs(now - filetime) 1 thennode.time filetime;update true;try_load(node);endendendend)__;
上面的定义是Hive在加载用户的文件之前会调用的。
主要关注import函数——
函数首先执行get_filenode函数。该函数首先到全局的hive.files表中进行查找如果找到了则直接返回该node这里的node其实就是一个表一个虚拟的沙箱。否则就新建一张表这张表的元表是固定的hive.meta即如果在该表中无法找到则到_G中进行查找。这里的_G事实上就是导入的文件的环境。如果是新导入的文件则对其进行加载即可记录下导入的时间方便后面检查是否有更新
Hive接口手册
除了前面章节中所提到的内容Hive其实还有一些其他的接口暴露给了用户。使用hive.xxx即可访问。
API作用get_version返回版本号get_file_time获取文件的修改时间get_full_path获取文件的绝对路径get_time_ms/get_time_ns获取当前的时间(Epoch格式)sleep_ms睡眠daemon服务作为后台运行