编写高性能的Lua代码

2016-12-16  本文已影响89人  IvanRunning

只要实战不说废话

变量

因为 Lua 的寄存器很多,预编译时便能将所有的局部变量存到寄存器中。所以,在 Lua 中访问局部变量是很快的。所以解决Lua性能问题,最重要的是用 local 去修饰变量。不使用 local 修饰的变量都是全局变量,在查询局部变量的时候要去全局表 _G 中查询,很耗时间。

除了这个明显的地方,另有几处也可使用局部变量,可以助你挤出更多的性能。比如,如果在很长的循环里调用函数,可以先将这个函数赋值给一个局部变量。这个代码:

for i = 1, 1000000 do  
  local x = math.sin(i)
end

下面的方法比上面的方法快30%

local sin = math.sin
for i = 1, 1000000 do
  local x = sin(i)
end

访问外层局部变量(也就是外一层函数的局部变量 up Value)并没有访问局部变量快,但是仍然比访问全局变量快。访问速度是这样的:first Value > up Value > global
考虑如下代码:

function foo(x)  
  for i = 1, 1000000 do   
    x = x + math.sin(i) 
  end
  return x
end

我们可以通过在 foo函数外面定义一个 sin来优化它:(local sin 就相当于 function fooup Value)

local sin = math.sin
function foo(x)  
  for i = 1, 1000000 do   
     x = x + sin(i) 
  end 
  return x
end
print(foo(10))

当 Lua 想在表中插入一个新的键值而哈希数组已满时,Lua 会做一次重新哈希(rehash),我们以往写程序的习惯是这么初始化表 a = {} 这个时候 Lua 是没有给 table 分配空间的。如果是下面的代码会发生什么:

local a = {}
for i =1, 3 do
  a[i] = true
end

这段代码触发了两次 rehash (一次分配2的指数值大小),如果是处理一个大数据,需要几万次的循环,可想而知 rehash 的次数将非常大,所以这样大大浪费了空间和性能。以后初始化表的时候如果如果知道表中有固定的值了,就直接构造进去。比如:
a = {true, true, true}

for i = 1, 1000000 do
  local a = {}
  a [1] = 1; a[2] = 2; a[3] = 3
end

这段代码运行了2.0s

其他

可以把不变的操作放在循环外

function foo (...) 
 for i = 1, n do   
   local t = {1, 2, 3, "hi"}    
   -- 做一些不改变 t 的操作   
   ... 
 end
end
local t = {1, 2, 3, "hi"} -- 一次性地创建 t
function foo (...)  
  for i = 1, n do    
    -- 做一些不改变 t 的操作   
     ... 
  end
end

很多字符串的处理,都可以通过在现有字符串上使用下标,来避免创建不必要的新字符串。例如,函数 string.find返回的是给定模式出现的位置,而不是一个与之匹配的字符串。返回下标,就避免了在成功匹配时创建一个新的子字符串。若有需要,可以再通过函数 string.sub 来获取匹配的子字符串。

上一篇下一篇

猜你喜欢

热点阅读