• 网上有大量对 Lua 调优的推荐,我们应该如何看待?

    网上有大量对 Lua 调优的推荐,我们应该如何看待?

    Lua 的解析器有官方的 standard Lua 和 LuaJIT,需要明确一点的是目前大量的优化文章都比较陈旧,而且都是针对 standard Lua 解析器的,standard Lua 解析器在性能上需要书写者自己规避,才能写出高性能来。需要各位看官注意的是,OpenResty 最新版默认已经绑定 LuaJIT,优化手段和方法已经略有不同。我们现在的做法是:代码易读是首位,目前还没有碰到同样代码换个写法就有质的提升,如果我们对某个单点功能有性能要求,那么建议用 LuaJIT 的 FFI 方法直接调用 C 接口更直接一点。

    代码出处:http://www.cnblogs.com/lovevivi/p/3284643.html

    1. 3.0 避免使用table.insert()
    2. 下面来看看4个实现表插入的方法。在4个方法之中table.insert()在效率上不如其他方法,是应该避免使用的。
    3. 使用table.insert
    4. local a = {}
    5. local table_insert = table.insert
    6. for i = 1,100 do
    7. table_insert( a, i )
    8. end
    9. 使用循环的计数
    10. local a = {}
    11. for i = 1,100 do
    12. a[i] = i
    13. end
    14. 使用tablesize
    15. local a = {}
    16. for i = 1,100 do
    17. a[#a+1] = i
    18. end
    19. 使用计数器
    20. local a = {}
    21. local index = 1
    22. for i = 1,100 do
    23. a[index] = i
    24. index = index+1
    25. end
    26. 4.0 减少使用 unpack()函数
    27. Luaunpack()函数不是一个效率很高的函数。你完全可以写一个循环来代替它的作用。
    28. 使用unpack()
    29. local a = { 100, 200, 300, 400 }
    30. for i = 1,100 do
    31. print( unpack(a) )
    32. end
    33. 代替方法
    34. local a = { 100, 200, 300, 400 }
    35. for i = 1,100 do
    36. print( a[1],a[2],a[3],a[4] )
    37. end

    针对这篇文章内容写了一些测试代码:

    1. local start = os.clock()
    2. local function sum( ... )
    3. local args = {...}
    4. local a = 0
    5. for k,v in pairs(args) do
    6. a = a + v
    7. end
    8. return a
    9. end
    10. local function test_unit( )
    11. -- t1: 0.340182 s
    12. -- local a = {}
    13. -- for i = 1,1000 do
    14. -- table.insert( a, i )
    15. -- end
    16. -- t2: 0.332668 s
    17. -- local a = {}
    18. -- for i = 1,1000 do
    19. -- a[#a+1] = i
    20. -- end
    21. -- t3: 0.054166 s
    22. -- local a = {}
    23. -- local index = 1
    24. -- for i = 1,1000 do
    25. -- a[index] = i
    26. -- index = index+1
    27. -- end
    28. -- p1: 0.708012 s
    29. -- local a = 0
    30. -- for i=1,1000 do
    31. -- local t = { 1, 2, 3, 4 }
    32. -- for i,v in ipairs( t ) do
    33. -- a = a + v
    34. -- end
    35. -- end
    36. -- p2: 0.660426 s
    37. -- local a = 0
    38. -- for i=1,1000 do
    39. -- local t = { 1, 2, 3, 4 }
    40. -- for i = 1,#t do
    41. -- a = a + t[i]
    42. -- end
    43. -- end
    44. -- u1: 2.121722 s
    45. -- local a = { 100, 200, 300, 400 }
    46. -- local b = 1
    47. -- for i = 1,1000 do
    48. -- b = sum(unpack(a))
    49. -- end
    50. -- u2: 1.701365 s
    51. -- local a = { 100, 200, 300, 400 }
    52. -- local b = 1
    53. -- for i = 1,1000 do
    54. -- b = sum(a[1], a[2], a[3], a[4])
    55. -- end
    56. return b
    57. end
    58. for i=1,10 do
    59. for j=1,1000 do
    60. test_unit()
    61. end
    62. end
    63. print(os.clock()-start)

    从运行结果来看,除了 t3 有本质上的性能提升(六倍性能差距,但是 t3 写法相当丑陋),其他不同的写法都在一个数量级上。你是愿意让代码更易懂还是更牛逼,就看各位看官自己的抉择了。不要盲信,也不要不信,各位要睁开眼自己多做测试。

    另外说明:文章提及的使用局部变量、缓存 table 元素,在 LuaJIT 中还是很有用的。