Skip to content

Latest commit

 

History

History
179 lines (148 loc) · 6.57 KB

what_jit.md

File metadata and controls

179 lines (148 loc) · 6.57 KB

什么是 JIT ?

自从 OpenResty 1.5.8.1 版本之后,默认捆绑的 Lua 解释器就被替换成了 LuaJIT ,而不在是标准 Lua。单从名字上,我们就可以直接看到这个新的解释器多了一个 JIT,接下来我们就一起来聊聊这个 JIT 是个什么东东。

我们先来看一下 LuaJIT 官方站点的解释: LuaJIT is a Just-In-Time Compilerfor the Lua programming language。

肯定有读者可能要问了,什么 Just-In-Time ?他的中文名称是即时编译器,是一个把程序字节码(包括需要被解释的指令的程序)转换成可以直接发送给处理器的指令的程序。

还没听懂?说的再直白一些,就是把 Lua 代码直接解释成 CPU 可以执行的指令,要知道原本 Lua 代码是只能在 Lua 虚拟机中运行,现在突然有办法让 Lua 代码一次编译后直接运行在 CPU 上,效率自然更胜一筹。

给这个 JIT 吹了半天,实用效果怎样?大家看下面例子:

➜ cat test.lua
local s = [[aaaaaabbbbbbbcccccccccccddddddddddddeeeeeeeeeeeee
fffffffffffffffffggggggggggggggaaaaaaaaaaabbbbbbbbbbbbbb
ccccccccccclllll]]

for i=1,10000 do
    for j=1,10000 do
        string.find(s, "ll", 1, true)
    end
end

➜ time luajit test.lua
5.19s user
0.03s system
96% cpu
5.392 total

➜  time lua test.lua
9.20s user
0.02s system
99% cpu
9.270 total

本例子可以看到效率相差大约 9.2/5.19 ≈ 1.77 倍,换句话说标准 Lua 需要 177% 的时间才能完成同样的工作。估计大家觉得这个还不过瘾,再看下面示例代码:

文件 test.lua:

local loop_count = tonumber(arg[1])
local fun_pair = "ipairs" == arg[2] and ipairs or pairs

local t = {}
for i=1,100 do
    t[i] = i
end

for i=1,loop_count do
    for j=1,1000 do
        for k,v in fun_pair(t) do
            --
        end
    end
end
执行参数 执行结果
time lua test.lua 1000 ipairs 3.96s user 0.02s system 98% cpu 4.039 total
time lua test.lua 1000 pairs 3.97s user 0.01s system 99% cpu 3.992 total
time luajit test.lua 1000 ipairs 0.10s user 0.00s system 95% cpu 0.113 total
time luajit test.lua 10000 ipairs 0.98s user 0.00s system 99% cpu 0.991 total
time luajit test.lua 1000 pairs 1.54s user 0.01s system 99% cpu 1.559 total

从这个执行结果中,大致可以总结出下面几个观点:

  • 在标准 Lua 解释器中,使用 ipairs 或 pairs 没有区别。
  • 对于 pairs 方式,LuaJIT 的性能大约是标准 Lua 的 4 倍。
  • 对于 ipairs 方式,LuaJIT 的性能大约是标准 Lua 的 40 倍。

本书中曾多次提及,尽量使用支持可以被 JIT 编译的 API。到底有哪些 API 是可以被 JIT 编译呢?我们的参考来来源是哪里呢?LuaJIT 的官方地址:http://wiki.luajit.org/NYI,需要最新动态的同学,不妨多看看这个地址的内容。下面我们把重要的几个库是否支持 JIT 的点罗列一下。

基础库的支持情况

函数 编译? 备注
assert yes
collectgarbage no
dofile never
error never
getfenv 2.1 partial 只有 getfenv(0) 能编译
getmetatable yes
ipairs yes
load never
loadfile never
loadstring never
next no
pairs no
pcall yes
print no
rawequal yes
rawget yes
rawlen (5.2) yes
rawset yes
select partial 第一个参数是静态变量的时候可以编译
setfenv no
setmetatable yes
tonumber partial 不能编译非10进制,非预期的异常输入
tostring partial 只能编译:字符串、数字、布尔、nil 以及支持 __tostring元方法的类型
type yes
unpack no
xpcall yes

字符串库

函数 编译? 备注
string.byte yes
string.char 2.1
string.dump never
string.find 2.1 partial 只有字符串样式查找(没有样式)
string.format 2.1 partial 不支持 %p 或 非字符串参数的 %s
string.gmatch no
string.gsub no
string.len yes
string.lower 2.1
string.match no
string.rep 2.1
string.reverse 2.1
string.sub yes
string.upper 2.1

函数 编译? 备注
table.concat 2.1
table.foreach no 2.1: 内部编译,但还没有外放
table.foreachi 2.1
table.getn yes
table.insert partial 只有 push 操作
table.maxn no
table.pack (5.2) no
table.remove 2.1 部分,只有 pop 操作
table.sort no
table.unpack (5.2) no

math 库

函数 编译? 备注
math.abs yes
math.acos yes
math.asin yes
math.atan yes
math.atan2 yes
math.ceil yes
math.cos yes
math.cosh yes
math.deg yes
math.exp yes
math.floor yes
math.fmod no
math.frexp no
math.ldexp yes
math.log yes
math.log10 yes
math.max yes
math.min yes
math.modf yes
math.pow yes
math.rad yes
math.random yes
math.randomseed no
math.sin yes
math.sinh yes
math.sqrt yes
math.tan yes
math.tanh yes

其他

其他还有 IO、Bit、FFI、Coroutine、OS、Package、Debug、JIT 等目录分类,使用频率相对较低,在这里就不逐一罗列,需要的同学可以到 http://wiki.luajit.org/NYI 查看。