LuaJIT FFI回调性能
LuaJIT FFI 文档提到,从 C 回调到 Lua 代码的调用相对较慢,并建议尽可能避免这种情况:
不要使用回调进行性能敏感的工作:例如,考虑一个需要对用户定义的函数进行积分运算的数值积分例程。在 C 代码中调用一个用户定义的 Lua 函数数百万次是个坏主意。回调开销对性能的影响将是十分不利的。
对于新设计,避免使用 PUSH-STYLE 的 API(C 函数重复调用每个结果的回调)。 相反,使用 PULL-STYLE 的 API(重复调用 C 函数以获取新的结果)。通过 FFI 从 Lua 到 C 的调用比另一种方式快得多。 大多数设计良好的库已经使用了 PULL-STYLE 的 API(读/写,获取/放置)。
然而,他们没有提供从 C 回调的速度相对缓慢的任何感觉。如果我有一些我想加速的代码,并且使用回调,如果我重写它以使用 PULL-STYLE 的 API ,我可以期望得到多少加速呢?有人有比较使用每种 API 样式实现等效功能的基准测试吗?
在我的电脑上,从LuaJIT调用C语言函数的开销为5个CPU时钟周期(值得注意的是,与通过指向C语言普通函数指针调用函数一样快),而从C语言回调Lua函数需要135个时钟周期的开销,慢了27倍。也就是说,如果一个程序需要一百万次从C语言回调Lua函数的调用,只会增加约100毫秒的运行时间开销;虽然在操作大部分在缓存中的数据的紧密循环中避免FFI回调可能是值得的,但是如果回调每次仅在I/O操作中被调用一次,那么与I/O本身的开销相比,回调的开销可能不会被注意到。
$ luajit-2.0.0-beta10 callback-bench.lua
C into C 3.344 nsec/call
Lua into C 3.345 nsec/call
C into Lua 75.386 nsec/call
Lua into Lua 0.557 nsec/call
C empty loop 0.557 nsec/call
Lua empty loop 0.557 nsec/call
$ sysctl -n machdep.cpu.brand_string
Intel(R) Core(TM) i5-3427U CPU @ 1.80GHz
两年后,我重新进行了 Miles 的答案 的基准测试,原因如下:
1.查看它们是否随着新的发展(CPU 和 LuaJIT)得到改进。 2.为具有参数和返回的函数添加测试。回调文档 提到除了调用开销之外,参数编组也很重要:
[...] C到Lua的转换本身具有无法避免的成本,类似于lua_call()或lua_pcall()。参数和结果编组增加了该成本[…]
3.检查PUSH样式和PULL样式之间的差异。
我的结果,在 Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz上:
operation reps time(s) nsec/call
C into Lua set_v 10000000 0.498 49.817
C into Lua set_i 10000000 0.662 66.249
C into Lua set_d 10000000 0.681 68.143
C into Lua get_i 10000000 0.633 63.272
C into Lua get_d 10000000 0.650 64.990
Lua into C call(void) 100000000 0.381 3.807
Lua into C call(int) 100000000 0.381 3.815
Lua into C call(double) 100000000 0.415 4.154
Lua into Lua 100000000 0.104 1.039
C empty loop 1000000000 0.695 0.695
Lua empty loop 1000000000 0.693 0.693
PUSH样式 1000000 0.158 158.256
PULL样式 1000000 0.207 207.297
这个结果的代码在这里。
结论:使用带有参数的 C 回调到 Lua 具有非常大的开销(这几乎是你经常做的),因此它们在关键点上真的不应该使用。不过,您可以将它们用于 IO 或用户输入。
我有点惊讶 PULL/PUSH 样式之间的差异很小,但也许我的实现不是最好的。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在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中获取用户配置主目录的跨平台方法
下面是这些结果所显示的显著的表现差异:
LuaJIT 2.0.0-beta10 (Windows x64) JIT: ON CMOV SSE2 SSE3 SSE4.1 fold cse dce fwd dse narrow loop abc sink fuse n 推时间 拉时间 推内存 拉内存 256 0.000333 0 68 64 4096 0.002999 0.001333 188 124 65536 0.037999 0.017333 2108 1084 1048576 0.588333 0.255 32828 16444 16777216 9.535666 4.282999 524348 262204此基准测试的代码可在此处找到。