补齐遗失副本,时间线回归。
本文同步发表於个人网站
现在,我们来尝试从C去执行一个Lua程序,Lua程序就用最简单的Hello,并命名为hello.lua
print "Hello"
然後来写C程序 -- hello_C.c
。
需要下载含有标头档和函式库的版本
#include "lua.h"
#include "lauxlib.h"
// new a lua VM
lua_State *L = luaL_newstate();
通常而言,不会全部开启所有功能。
这只是范例,让hello.lua
档案拥有所有能力。
// open all libraries
luaL_openlibs(L);
luaL_dofile(L, "hello.lua");
#include "lua.h"
#include "lauxlib.h"
int main(int argc, char *argv[]){
// new a lua VM
lua_State *L = luaL_newstate();
// open all libraries
luaL_openlibs(L);
// dofile
luaL_dofile(L, "hello1");
return 0;
}
Hello
如此一来可以随意更动
hello.lua
档案,而无须重新编译C程序。
目录结构:
接者要来尝试从C实现以下Lua函数:
function hello(name)
print("Hello, World")
end
不过在此之前,得先了解到,Lua与C交互,是抽象在一个平坦的记忆体堆叠空间,通常总是从堆叠上放存取会放置资料。写过组合语言的可能会这种模式会有些熟悉。
int CHello(lua_State *L){
const char *name = lua_tostring(L,-1); // 从堆叠顶部取得一个字串
lua_pop(L, 1); // 将字串弹出堆叠
printf("Hello, %s\n", name);
return LUA_OK;
}
最好还去检查输入的参数型别是否正确。
在错误处理曾经处理过。
lua_register(L, "CHello", CHello);
CHello("World")
#include "lua.h"
#include "lauxlib.h"
#include <stdio.h>
int CHello(lua_State*);
int main(int argc, char *argv[]){
// new a lua VM
lua_State *L = luaL_newstate();
// open all libraries
luaL_openlibs(L);
// regist C function to Lua
lua_register(L, "CHello", CHello);
// dofile
luaL_dofile(L, "chello.lua");
return 0;
}
int CHello(lua_State *L){
const char *name = lua_tostring(L,-1); // 从堆叠顶部取得一个字串
lua_pop(L, 1); // 将字串弹出堆叠
printf("Hello, %s\n", name);
return 0; // no return. 多回传值时,填入回传数目。这个函数没有回传值,故为0。
}
在C无法除0:
double x = 1.0 / 0; // Error: 无法除0
虽然在C写
1.0 / 0
会报错,但是可以写1 / 0.0
。这与C自动转型有关。
Lua在这部份处理的更人性化,但尽管Lua可以直接写1 / 0
,你仍应该知道背後的原因。
不过在Lua可以除0,会得到无限大:
x = 1 / 0 -- inf
虽然Lua的数字也有限制,但可能比C来的更安全。现在,希望使用部份Lua数值计算的能力:
function div(a,b)
return a/b
end
div
,他会被放至於堆叠顶部。lua_Number LuaDiv(lua_State *L, lua_Number a, lua_Number b){
int get_type = lua_getglobal(L, "div"); // get Lua Function
/* check th global variable -- div, is a Lua Function
if(get_type == LUA_TFUNCTION){
printf("[in C] is Lua Function.\n");
}
if(lua_isfunction(L, -1)){ // check top of stack is Lua Function
printf("[in C] top of stack is Lua Function.\n");
}
*/
lua_pushnumber(L, a); // pass paramter
lua_pushnumber(L, b); // pass paramter
lua_call(L, /*nargs = */ 2, /* nresult = */ 1); //两个输入,一个回传值。
lua_Number result = lua_tonumber(L, -1); // 取得回传值
lua_pop(L, 1);
return result; // 回传结果
}
#include "lua.h"
#include "lauxlib.h"
lua_Number LuaDiv(lua_State *L, lua_Number a, lua_Number b);
int main(int argc, char *argv[]){
// new a lua VM
lua_State *L = luaL_newstate();
// open all libraries
luaL_openlibs(L);
// dofile
luaL_dofile(L, "div.lua"); // load Lua's div function
double r = LuaDiv(L, 1, 0);
printf("1 / 0 = %f\n", r);
return 0;
}
lua_Number LuaDiv(lua_State *L, lua_Number a, lua_Number b){
int get_type = lua_getglobal(L, "div"); // get Lua Function
/* check th global variable -- div, is a Lua Function
if(get_type == LUA_TFUNCTION){
printf("[in C] is Lua Function.\n");
}
if(lua_isfunction(L, -1)){ // check top of stack is Lua Function
printf("[in C] top of stack is Lua Function.\n");
}
*/
lua_pushnumber(L, a); // pass paramter
lua_pushnumber(L, b); // pass paramter
lua_call(L, /*nargs = */ 2, /* nresult = */ 1); //两个输入,一个回传值。
lua_Number result = lua_tonumber(L, -1); // 取得回传值
lua_pop(L, 1);
return result; // 回传结果
}
本小节参考:Lua:一个Python的秘密武器
我很好奇Lua到底能否作为Python的加速,照着Lua:一个Python的秘密武器做了一次。
import time
import random
size = 5000_000
st = time.time()
a = [random.randint(1, size) for _ in range(size)]
b = [random.randint(1, size) for _ in range(size)]
print("Pure Python init", time.time() - st)
def test():
for i in range(size):
if a[i] != b[i]:
a[i] = a[i] + b[i]
st = time.time()
test()
print("Pure Python Sum", time.time() - st)
以下是使用Python 3.8.2,於LinuxMint 20.3执行的结果。
Pure Python init 29.92748188972473
Pure Python Sum 2.812898635864258
接着是使用lupa
的结果
from lupa import LuaRuntime
lua = LuaRuntime()
lua_code = r'''
function (size)
a = {}
b = {}
st = os.clock()
for i=0, size-1 do
a[i] = math.random(size)
end
for i=0, size-1 do
b[i] = math.random(size)
end
print("Lua init: " .. (os.clock() - st))
st = os.clock()
for i = 0, size - 1 do
if a[i] ~= b[i] then
a[i] = a[i] + b[i]
end
end
print("Lua sum: " .. (os.clock() - st))
end
'''
test = lua.eval(lua_code)
size = 5000_000
test(size)
Lua init: 2.650081
Lua sum: 1.75244
Pure Python init 4.170244216918945
Pure Python Sum 0.04040670394897461
我没有去尝试Numpy和C的版本。其实还有Cython的方式可以加速Python程序。但就我看法,要为了加速而使用Lua有点不太有价值。在我的测试中,Lua初始化快了许多,但Lua的数值型态与Python的也有差异。Python的整数可以到非常之大,端看记忆体大小。当然,如果你确定你的资料值域,有可能使用Lua进行加速是恰当的。
userdata
是从C语言定义的资料型态。分成两种形式:
full userdata完全有Lua掌控,包含创建与记忆体回收。相对的light userdata其实就只是一个C指标而已。
本系列未打算对userdata
多做讲解,各位只要了解到其有两种型态,并且所有操作,其实都是由C定义即可。
>>: Day 30. Hugo 系列文回顾,铁人赛反省与获得
接下来几天的文章会像料理节目一样,用我事先准备好的材料 (模型、App...) 来进行说明,底下就来...
虽然还有另一个按纽,但是今天我想先来玩玩内联模式 前置作业 还记得 Day04 - Telegra...
因缘际会,写这次铁人赛内容时会使用不同台电脑做登入操作 WordPress 上的功能,因此会开设无痕...
CheckBox中文叫核取方块 看过很多次这种元件,但一直不知道中文叫什麽 这也是一种选择的元件 和...
这是铁人赛的最後一篇文章,我想在这个结尾分享为什麽我会写这个主题,这是因为几个月前的某一天我正在与跨...