对象基准测试

lua-users home
wiki

本文评估了 Lua 中各种面向对象方法的对象访问时间。主要关注的是原始性能速度,而不是内存使用或对象创建时间。

代码

-- Benchmarking support.
do
  local function runbenchmark(name, code, count, ob)
    local f = loadstring([[
        local count,ob = ...
        local clock = os.clock
        local start = clock()
        for i=1,count do ]] .. code .. [[ end
        return clock() - start
    ]])
    io.write(f(count, ob), "\t", name, "\n")    
  end

  local nameof = {}
  local codeof = {}
  local tests  = {}
  function addbenchmark(name, code, ob)
    nameof[ob] = name
    codeof[ob] = code
    tests[#tests+1] = ob
  end
  function runbenchmarks(count)
    for _,ob in ipairs(tests) do
      runbenchmark(nameof[ob], codeof[ob], count, ob)
    end
  end
end

function makeob1()
  local self = {data = 0}
  function self:test()  self.data = self.data + 1  end
  return self
end
addbenchmark("Standard (solid)", "ob:test()", makeob1())

local ob2mt = {}
ob2mt.__index = ob2mt
function ob2mt:test()  self.data = self.data + 1  end
function makeob2()
  return setmetatable({data = 0}, ob2mt)
end
addbenchmark("Standard (metatable)", "ob:test()", makeob2())

function makeob3() 
  local self = {data = 0};
  function self.test()  self.data = self.data + 1 end
  return self
end
addbenchmark("Object using closures (PiL 16.4)", "ob.test()", makeob3())

function makeob4()
  local public = {}
  local data = 0
  function public.test()  data = data + 1 end
  function public.getdata()  return data end
  function public.setdata(d)  data = d end
  return public
end
addbenchmark("Object using closures (noself)", "ob.test()", makeob4())

addbenchmark("Direct Access", "ob.data = ob.data + 1", makeob1())

addbenchmark("Local Variable", "ob = ob + 1", 0)


runbenchmarks(select(1,...) or 100000000)

结果(当前版本)

以下是当前版本的结果。所有时间均以秒(如果您的操作系统支持,则以秒和亚秒)为单位,表示 1 亿次迭代(1e8,默认值)。
| 2010-01-15 MikePall
| Intel Core2 Duo E8400 3.00GHz
| Linux x86, GCC 4.3.3 (-O2 -fomit-frame-pointer for both Lua and LuaJIT)
| Lua 5.1.4 (lua objbench.lua) vs.
| LuaJIT 1.1.5 (luajit -O objbench.lua) vs.
| LuaJIT 2.0.0-beta2 (lj2 objbench.lua)

Lua     LJ1    LJ2
-----------------------------------------------------
14.08	2.16   0.1  Standard (solid)
14.92	4.62   0.1  Standard (metatable)
14.28	2.66   0.1  Object using closures (PiL 16.4)
 9.14	1.68   0.1  Object using closures (noself)
 7.30   1.10   0.1  Direct Access
 1.22	0.34   0.1  Local Variable

| 2008-04-16 MikePall
| Intel Core2 Duo E6420 2.13GHz
| Linux x86, GCC 4.1.2 (-O3 -fomit-frame-pointer for both Lua and LuaJIT)
| Lua 5.1.3 (lua objbench.lua) vs. LuaJIT 1.1.4 (luajit -O objbench.lua)

17.93   3.11   Standard (solid)
20.36   6.25   Standard (metatable)
19.34   3.73   Object using closures (PiL 16.4)
12.76   2.23   Object using closures (noself)
 7.53   1.55   Direct Access
 2.59   0.47   Local Variable

| 2008-04-17 LeonardoMaciel
| Intel Core 2 Duo T7200 2.00 GHz
| WinXP, MSVC9 (VS 2008)
| Lua 5.1.3 (using luavs.bat) vs. LuaJIT 1.1.4 (using luavs.bat)
| [NOTE: this measurement probably didn't use luajit -O]

17.52  10.78  Standard (solid)
19.74  12.55  Standard (metatable)
18.31  10.88  Object using closures (PiL 16.4)
14.20   5.09  Object using closures (noself)
 7.99   5.94  Direct Access
 1.70   0.41  Local Variable

| 2008-04-19 DougCurrie
| Pentium M 2.00 GHz
| WinXP, GCC 3.4.5 (mingw special)
| Lua 5.1.3 (from wxLua build) vs. LuaJIT 1.1.4 (luajit -O objbench.lua)

28.68   4.76  Standard (solid)
31.23   9.49  Standard (metatable)
30.32   5.38  Object using closures (PiL 16.4)
19.60   3.27  Object using closures (noself)
12.47   2.26  Direct Access
 2.72   0.51  Local Variable

<--- Add your results here if you like.
<--- Please indicate the date and your name or wiki page.
<--- Add your CPU, OS, compiler and Lua and/or LuaJIT version.

结果(旧版本)

以下是旧版本的结果,缺少“局部变量”测试,并以秒为单位测量经过时间。
Windows XP SP2  Intel P4 1.8a

Standard (solid)  Time: 34
Standard (metatable)  Time: 37
Object using closures (PiL 16.4)  Time: 40
Object using closures (noself)  Time: 29
Direct Access  Time: 19
Windows XP x64 SP1  AMD Athlon64 3500+ (64-bit Lua)

Standard (solid)  Time: 22
Standard (metatable)  Time: 23
Object using closures (PiL 16.4)  Time: 25
Object using closures (noself)  Time: 18
Direct Access  Time: 11
Windows Vista Ultimate(32bit), AMD Athlon X2 4200+ (Vanilla Lua 5.1.1 / LuaJIT 1.1.2)

Standard (solid)  Time: 26 / 11
Standard (metatable)  Time: 29 / 15
Object using closures (PiL 16.4)  Time: 30 / 12
Object using closures (noself)  Time: 20 / 6
Direct Access  Time: 13 / 8
Linux Xubuntu Feisty Fawn(32bit), Intel P4 Celeron 2.4ghz (Vanilla Lua 5.1.1)

Standard (solid)  Time: 34
Standard (metatable)  Time: 38
Object using closures (PiL 16.4)  Time: 40
Object using closures (noself)  Time: 25
Direct Access  Time: 20
Windows XP Prof. SP2, Intel PIII 500mhz (Vanilla Lua 5.1.1 / LuaJIT 1.1.2)

Standard (solid)  Time: 133 / 60
Standard (metatable)  Time: 146 / 76
Object using closures (PiL 16.4)  Time: 147 / 64
Object using closures (noself)  Time: 99 / 32
Direct Access  Time: 67 / 36

结论

直接访问表本地副本是迄今为止最快的执行方式(正如预期的那样)。这作为其他方法的参考。

noself 方法在这里是第二快的。它严格依赖于闭包和在该闭包中定义的局部变量,只返回公共接口。如果测试被修改为每次方法调用执行十次加法,那么它可以超过直接访问的速度,因为这减少了函数调用的开销。noself 和 PiL 16.4 方法是唯一两个支持私有作用域变量的方法。

其他所有方法都比标准直接访问慢。元表方法由于需要额外的查找而使工作变得更加复杂,但其速度仍然与 PiL 16.4 方法相当。

PiL 16.4 中提到的方法添加了私有作用域优势,并使用闭包来存储 self,但这远不如 Lua 在使用适当的 'self' 时所做的优化快。

最后要说明的一点是:早期版本的基准测试代码没有对对象进行本地引用(而是索引全局表)。这会影响所有方法,使其速度降低几秒钟,其中直接访问受到的影响最大——时间翻了一番。

希望这有帮助——AA


如果您认为您的规格有价值,请随时在上面添加您的规格。请运行三次并使用平均值。

另请参阅


最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2012 年 2 月 25 日凌晨 12:45 GMT (差异)