Hive 浅析
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 = {__index=function(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 = {env=env, fullpath=fullpath, filename=filename};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 | 服务作为后台运行 |
相关文章:

Hive 浅析
Hive是一个简单的LUA沙盒,除了基本的LUA解释器的功能以外,还提供了诸如热加载等功能。 了解HIVE的工作原理有利于了解Lua虚拟机的底层实现机理。 本文从是什么-怎么用-为什么三个维度介绍HIVE。 Hive Hive是什么 hive是一个简单的LUA应用框架,目前基于…...

C 语言中,结构体「.」与「->」的区别
简单来说 「 」的左边是结构体名字时用点符号「.」 「 」的左边是结构体指针时名字时用箭头「->」 对于要读取结构体种的数据时,有下面三种写法,操作是等价的。 struct ListNode a;struct ListNode *p1 &a;/*三种写法*/a.element 2333;p1->e…...

【Java Web学习笔记】5 - XML
项目代码 https://github.com/yinhai1114/JavaWeb_LearningCode/tree/main/xml 零、在线文档 XML系列教程 一、XML引出 1.为什么需要XML 1.需求1 :两个程序间进行数据通信? 2.需求2:给一台服务器,做一个配置文件,当服务器程序启动时,去…...

在jupyter notebook中修改其他文件的解决方案
大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

如何在Android中旋转屏幕时避免重新绘制Activity
如何在Android中旋转屏幕时避免重新绘制Activity 在Android开发中,设备旋转通常导致当前活动(Activity)被销毁并重新创建,这可能导致用户界面重置和不必要的资源重新加载。然而,有时我们希望避免这种行为,…...

离线环境下安装python库(推荐pip download)
离线环境下安装python库(推荐pip download) 目录 1.需求 2.失败操作(注意) 3.成功操作 4.其它参考 1.需求 机器部署web系统环境后,就不可再次联网,所以升级python web后端,需要离线安装pyt…...

ubuntu16.04安装ROS+Gazebo
ubuntu16.04安装ROS参考文章 ros安装(一键最简安装,吹爆鱼香ROS,请叫我鱼吹) ROS篇——Ubuntu快速一键安装ROS或ROS2(通用) ubuntu安装ROS melodic(最新、超详细图文教程) 配置ubuntu以及安装ros2必要环…...

手动搭建koa+ts项目框架(路由篇)
文章目录 前言一、安装koa-router二、引入koa-router并使用三、优化路由配置总结如有启发,可点赞收藏哟~ 前言 本文基于手动搭建koats项目框架(基础篇)配置接口路由 一、安装koa-router npm i -S koa-router二、引入koa-router并使用 ./sr…...

c语言:文件操作(1)
前言:为什么要使用文件 使用文件可以让程序在不同运行之间保存和读取数据。这样可以实现持久化存储,即使程序关闭后数据也不会丢失。文件也可以用于数据交换,允许不同程序之间共享信息。在 C 语言中,文件还可以用于读取配置信息&…...

运筹学经典问题(三):最大流问题
问题描述 给定一个图网络 G ( V , E ) G(V, E) G(V,E),网络中连边的权重代表最大容量,在这个图中找出从起点到终点流量最大的路径。 数学建模 集合: I I I:点的集合; E E E:边的集合。 常量&#x…...

裸机开发与Linux驱动开发的区别
一. 简介 裸机开发,即我们常说的不带系统的单片机开发。 Linux驱动开发,即带文件系统的Linux驱动的开发。 二. 裸机开发与Linux驱动开发的区别 1. 裸机开发 比较底层,跟寄存器打交道,有些 MCU提供了库。 2. Linux驱动开发…...

【蓝桥杯选拔赛真题75】Scratch行走的螃蟹 第十五届蓝桥杯scratch图形化编程 少儿编程创意编程选拔赛真题解析
目录 scratch行走的螃蟹 一、题目要求 编程实现 二、案例分析 1、角色分析...

小型洗衣机哪个牌子质量好?迷你洗衣机排名前十名
随着内衣洗衣机的流行,很多小伙伴在纠结该不该入手一款内衣洗衣机,专门来洗一些贴身衣物,答案是非常有必要的,因为我们现在市面上的大型洗衣机只能做清洁,无法对我们的贴身衣物进行一个高强度的清洁,而小小…...

MySQL_9.B-数索引
1.定义:B-树是一类树,包括B-树、B树、B*树等,是一棵自平衡的搜索树,它类似普通的平衡二叉树,不同的一点是B-树允许每个节点有更多的子节点. 2.B-数产生的原因 当数据量非常大时,内存不够用,大部分数据只能存放在磁盘上,只有需要的…...

ubuntu-更改镜像源-系统初始化-安装Clion-C++编译环境-Java安装
文章目录 1.镜像配置文件及更新2.安装java sdk并配置环境变量3.安装Clion4.总结 1.镜像配置文件及更新 将sources.list备份保存为sources.list.backup,以防止有需要的时候更换回来。 sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup sudo gedit /etc/apt/source…...

c语言-动态内存管理
文章目录 一、为什么会有动态内存管理二、申请内存函数1、malloc2、free3、calloc4、realloc 三、常见的动态内存的错误四、练习 一、为什么会有动态内存管理 1.我们一般的开辟空间方式: int a 0;//申请4个字节空间 int arr[10] { 0 };//申请40个字节空间2.这样…...

【JAVA杂货铺】一文带你走进面向对象编程的构造方法 | Java| 面向对象编程 | (中)
🌈个人主页: Aileen_0v0🔥系列专栏:Java学习系列专栏💫个人格言:"没有罗马,那就自己创造罗马~" 目录 回顾 构造方法 this关键字 面试题 构造方法的类型 下节预告 代码块 🍒回顾 之前我们学习了什么是类 什么是…...

动态规划学习——通符串匹配,正则表达式
目录 编辑 一,通符串匹配 1.题目 2.题目接口 3,解题思路及其代码 二,正则表达 1.题目 2.题目接口 3.解题思路及其代码 三,交错字符串 1.题目 2,题目接口 3.解题思路及其代码 一,通符串匹配 1…...

【数据开发】Hive 多表join中的条件过滤与指定分区
1、条件过滤 left join 中 on 后面加条件 where 和 and 的区别 1、 on条件是在生成临时表时使用的条件,它不管and中的条件是否为真,都会保留左边表中的全部记录。2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有le…...

基于Java SSM框架实现高校人事管理系统项目【项目源码】计算机毕业设计
基于java的SSM框架实现高校人事管理系统演示 JSP技术介绍 JSP技术本身是一种脚本语言,但它的功能是十分强大的,因为它可以使用所有的JAVA类。当它与JavaBeans 类进行结合时,它可以使显示逻辑和内容分开,这就极大的方便了用户的需…...

[C++] 模板进阶(非类型模板参数,特化,分离编译)
文章目录 1、非类型模板参数2、模板的特化2.1 什么是模板特化2.2 函数模板特化2.3 类模板的实例化2.3.1 全特化2.3.2 偏特化 3、模板分离编译3.1 什么是分离编译3.2 模板的分离编译3.3 解决方法 4、模板总结 1、非类型模板参数 模板参数分类类型形参与非类型形参。 类型形参即…...

C++ this指针
通常情况下,类的成员函数都只涉及一个对象,即调用它的对象。但有时候方法可能涉及到两个对象,在这种情况就需要使用到C的this指针。 class Stock { private: ... double total_val; ... public: double total() const {return total_val;} }…...

解决Sortable拖动el-table表头时,由于选择列造成的拖拽顺序错乱的bug
原因 由于我的表头是由数组循环遍历生成的,而选择列不在数组内,只能在循环外定义el-table-column,造成拖动时索引错乱错误代码 <el-tableheader-dragend"headerDragend"id"out-table":data"state.sliceTable&quo…...

Plantuml之类图语法介绍(十六)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...

深入Docker命令行:探索常用命令和实用技巧
Docker命令行界面是每个容器开发者的得力工具。在这篇文章中,将深入探讨一系列常用的Docker命令,以及一些实用技巧,通过更丰富的示例代码,帮助大家更全面地理解和运用Docker命令行工具。 1. Docker基本命令 1.1 镜像操作 深入了…...

qt 容器QVector,QMap,QHash的常见使用与该迭代器的简单介绍
一. QVector容器是一个动态数组,可以容纳任意数量的元素,在相邻的内存中存储给定的数据类型作为一组数据,在QVector前部或中间位置插入元素都会导致内存中大量的数据元素移动,这使得操作速度会减慢.可使用迭代器对这组数据进行访问. 和其他的容器类型类似,QVector…...

两线制无源 4-20mA 回路供电隔离变送器
两线制无源 4-20mA 回路供电隔离变送器 一入一出两线制无源 4-20mA 回路供电隔离变送器 概述:JSD TAW-1001D-100L-F 系列隔离变送器是 4-20mA 两线制回路供电的电流隔离变送配电器,该隔离变送器采用电磁隔离技术,并通过输入端馈电方式,给输入端两线制仪器仪表设备供…...

强化学习优质博客记录(随缘更新)
杂记 速成深度强化学习的人可能陷入的几个误区(2023-03更新) DQN DQN表现稳定提升和收敛的技巧集锦 TRPO 如何看懂TRPO里所有的数学推导细节? PPO The 37 Implementation Details of Proximal Policy Optimization强化学习算法中,PPO算法是不是就是加了重要…...

RabbitMQ-hello
0. pom文件 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0…...

案例044:基于微信小程序的消防隐患在线举报系统
文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…...