Lua FFI 实战 May 19, 2013由来FFI库,是LuaJIT中最重要的一个扩展库。它允许从纯Lua代码调用外部C函数,使用C数据结构。有了它,就不用再像 FFI简介FFI库,允许从纯Lua代码调用外部C函数,使用C数据结构。 FFI库最大限度的省去了使用C手工编写繁重的Lua/C绑定的需要。不需要学习一门独立/额外的绑定语言——它 FFI紧紧的整合进了LuaJIT(几乎不可能作为一个独立的模块)。JIT编译器为Lua代码直接访问C数据结构而产生的代码,等同于一个C编译器应该生产的代码。在JIT编译过的代码中,调用C函数,可以被 这一页将简要介绍FFI库的使用方法。 激励范例:调用外部C函数真的很用容易去调用一个外部C库函数:
以上操作步骤,如下:
事实上,背后的实现远非如此简单:③ 使用标准C库的命名空间 Ok,使用
Bing! 再一次, 远非如此简单,不? 和要求使用Lua/C API去绑定函数的努力相比:
传统的处理方式
唷!(很不爽呀!) 激励示例: 使用C数据结构FFI库允许你创建,并访问C数据结构。当然,其主要应用是C函数接口。但,也可以独立使用。 Lua构建在高级数据类型之上。它们很灵活、可扩展,而且是动态的。这就是我们大家都喜欢Lua的原因所在。唉,针对特殊任务,你需要一个低级的数据结构时,这可能会低效。例如,一个超大的不同结构的数组,需要通过一张超大的表,存储非常多的小表来实现。这需要大量的内存开销以及性能开销。 这里是一个库的草图,操作一个彩图,以及一个基准。首先,朴素的Lua版本,如下:
以上代码,创建一个160.000像素的一张表,其中每个元素是一张持有4个范围0至255的数字值的表。首先,创建了一张绿色斜坡的图(1D,为了简单化),然后进行1000次灰阶转换操作。实在很蠢蛋,可是我需要一个简单示例…… 以下是FFI版本代码。其中,被修改的部分加粗标注: ① local ffi = require("ffi") ffi.cdef[[ typedef struct { uint8_t red, green, blue, alpha; } rgba_pixel; ]] ② local function image_ramp_green(n) local img = ffi.new("rgba_pixel[?]", n) local f = 255/(n-1) ③ for i=0,n-1 do ④ img[i].green = i*f img[i].alpha = 255 end return img end local function image_to_grey(img, n) ③ for i=0,n-1 do ⑤ local y = 0.3*img[i].red + 0.59*img[i].green + 0.11*img[i].blue img[i].red = y; img[i].green = y; img[i].blue = y end end local N = 400*400 local img = image_ramp_green(N) for i=1,1000 do image_to_grey(img, N) end Ok, 这是不是太困难: ① 首先,加载FFI库,声明底层数据类型。这里我们选择一个数据结构,持有4字节字段,每一个由 ② 通过 ③ C数据是基于0的(zero-based),所以索引必须是0 到 n-1。你可能需要分配更多的元素,而不仅简化转换一流代码。 ④ 由于 ⑤ 调用 现在让我们看一下主要影响的变更: 首先,内存消耗从22M降到640K(4004004字节)。少了 其次,性能:纯Lua版本运行耗时9.57秒(使用Lua解析器52.9秒),而FFI版本在我的主机上耗时0.48秒(YMMV: 因人而异)。快了 狂热的读者,可能注意到了为颜色将纯Lua代码版本转为使用数组索引([1] 替换 .red, [2] 替换 .green 等)应该更加紧凑和更快。这个千真万确(大约 虽然最终的代码不是惯用的,而容易出错。它仍然没有得到甚至接近FFI版本代码的性能。同时,高级数据结构不容易传递给别的C函数,尤其是I/O函数,没有过分转换处罚。
扩展阅读
安装LuaJIT
|
|