一. 前言
本文为luajit作者所写文章Numerical Computing Performance Guide的译文,属于个人记录。
二. 指引
Lua涉及到计算的时候,会有很多错误的应用导致程序性能受到较大影响,各种错误情况及对应处理方案如下。
- 减少无法预知的分支数
- 有极高可能性偏向一方的条件分支不会影响(95%以上)
- 可以改用无分支的算法替换,如
- 使用
math.min()
和math.max()
- 使用
bit.*
库
- 使用
- 使用
FFI
数据结构- 使用
int32_t
,避免使用uint32_t
类型 - 使用
double
,避免使用float
- 不要滥用元方法
- 使用
- 仅通过
FFI
调用C函数- 避免调用很小的函数,更好的做法是在Lua重写
- 避免回调函数,使用推送(
read/write
)或者迭代器来代替
- 使用诸如
for i=start,stop,step do ... end
的循环语句- 数组索引也类似, e.g.
a[i+2].
- 避免使用指针计算
- 数组索引也类似, e.g.
- 展开适度
- 避免循环量少的内联循环
- 当且仅当循环体有太多指令时展开循环
- 考虑使用模板代替手动展开(如GSL Shell)
- 最好仅在模块(module)内定义并调用函数
- 对于其他模块的函数,如果常用,则缓存为上值(upvalue)
- 如,
local sin = math.sin
- 对于FFI C的函数不要这么做,缓存名字空间即可,如
local lib = ffi.load("lib")
- 如,
- 避免自己创建派遣机制,而是改用系统自带的,如元方法
- 不要过度优化,JIT编译器可能已经优化过了
- 例如,
z = x[a+b] + y[a+b]
的写法是没有问题的,如果手动增加一个临时变量存放a+b
,不仅不会提升性能,还会导致多占用了一个寄存器或者栈空间,得不偿失 - 例如,
a[i][j] = a[i][j] * a[i][j+1]
也一样没有问题 - 在使用LuaJIT的时候,这些细小的优化点编译器均帮忙做了更优的实现,程序员更需要关心的是更为宏大的优化,如算法复杂度的优化
- 例如,
- 不同于C/JAVA,变量的声明和定义尽量放在要用的地方,而不是函数开头
- 不要过度使用昂贵或未编译的操作
- 如
assert(type(x) == "number", "x is a "..mytype(x)")
,该语句最大的问题在于字符串拼接,该操作无论断言是否生效均需要每次操作 - 通过
-jv/-jdump
来看output确认是否有不需要的操作
- 如