2023年11月29日发(作者:)
Unity中SLua、Tolua、XLua和ILRuntime效率评测
Unity脚本效率评测
⽤例版本
Unity5.6.0p3
SLua 1.3.2
Tolua# github 2017/4/25 19:08:37
XLua 2.1.7
ILRuntime 1.11
Lua: luajit-2.1.0-beta2
测试环境
Smartian T2、Win7(64bit)
实验⽅案
总共设计了17个Test,分别从以下3个⽅⾯来考察脚本效率(JIT和⾮JIT),实验结果取10次的平均值,时间单位为ms。通过实验数据简
单分析原因(Lua插件会横向对⽐,ILRuntime会单独考虑,因为毕竟C#和Lua本⾝差别较⼤)。
1. Mono -> Script,Mono调⽤脚本
2. Script -> Mono,脚本调⽤Mono
3. Script⾃⾝,脚本⾃⾝执⾏效率
Mono -> Script
Test11Test12Test13Test14Test15Test16Sum
Tolua1864495984075777592978
SLua315751901757125318835863
XLua1459241010573150719296091
ILRuntime7114223683793973932672
Tolua(JIT)1684545924165788263037
SLua(JIT)384842956824132834397775
XLua(JIT)1899571047608154017006043
ILRuntime(JIT)1232892903969117511026275
Lua分析:
-- Test11
function EmptyFunc()
_V0 = _V0 + 1
end
_V0 = 1 -- Test12
_V1 = "12345" -- Test13
_V2 = () -- Test14
_V3 = (1, 2, 3) -- Test15
_V4 = {1, 2, 3} -- Test16
Test11为Mono调⽤脚本中空⽅法,Test12~16为测试Mono到脚本中取变量(ILRuntime代码类似,访问类的static函数与变量)。
ILRuntime因为没有变量类型的转换所以效率最为优秀(JIT模式下使⽤的是Mono的反射取值所以会更慢,ILRuntime内部可能对类型变量
有缓存,所以⽐反射快很多),Lua中可以看到Tolua的综合性能尤为突出(所有测试均好于其他Lua)。
对⽐Tolua和SLua的实现发现,Tolua会尽量减少与C++通信的次数,因为c#与c++通信会有⼀定效率损耗(参数的Marshaling等),虽
然是Mono与Lua通信,但是其中还夹着⼀层C++,所以Mono与Lua通信的主要优化思路就是减少与C++的通信,从实验数据来看Tolua的
这种优化效果是很明显的。
// SLua的函数调⽤
public bool pcall(int nArgs, int errfunc)
{
if (!Thread())
{
or("Can't call lua function in bg thread");
return false;
}
_getref(L, valueref);
if (!_isfunction(L, -1))
{
_pop(L, 1);
throw new Exception("Call invalid function.");
}
_insert(L, -nArgs - 1);
if (_pcall(L, nArgs, -1, errfunc) != 0)
{
_pop(L, 1);
return false;
}
return true;
}
// Tolua的函数调⽤
public void Call()
{
BeginPCall();
PCall();
EndPCall();
}
public int BeginPCall(int reference)
{
return _beginpcall(L, reference);
}
public int LuaPCall(int nArgs, int nResults, int errfunc)
{
return _pcall(L, nArgs, nResults, errfunc);
}
public void LuaSetTop(int newTop)
{
_settop(L, newTop);
}
对⽐SLua和Tolua代码的函数调⽤部分,发现SLua的C++调⽤多余Tolua两倍左右,所以效率⾼下⽴见。变量读取读者可以⾃⾏对⽐,总
结就是Tolua通过减少C++调⽤的⽅式来优化效率,后期对Lua的进⼀步优化也要遵循这个思路。
ILRuntime分析:
实验发现解释执⾏下,ILRuntime的获取变量的效率要明显好于Lua,主要是因为都是C#对象,不需要进⾏类型转换。ILRuntime的JIT模
式其实是⽤的Mono的,效率反⽽⽐解释执⾏更低,猜测是因为JIT下主要采⽤反射调⽤函数和取变量,⽽ILRuntime的解释器可能内部有缓
存(因为没看过实现,都是不负责任猜测)。
Script->Mono
Test0Test1Test2Test3Test4Test5Test6Test7Test10Sum
Tolua675797141035483934340716819157426
SLua768640230546611104083943379129910774
XLua59064885044507751213695126784514989
ILRuntime11521054401231599843710263272143413703
Tolua(JIT)6127017.4357823318371288843871
SLua(JIT)7326795.446511974111016513074974
XLua(JIT)63666883124387671303734134091115113
ILRuntime(JIT)721978426040233219303771651
Lua分析:
function Test0(transform)
local t = ()
for i = 1,200000 do
on = on
end
return () - t
end
function Test1(transform)
local t = ()
for i = 1,200000 do
transform:Rotate(up, 1)
end
return () - t
end
function Test2()
local t = ()
for i = 1, 2000000 do
local v = (i, i, i)
local x,y,z = v.x, v.y, v.z
end
return () - t
end
function Test3()
local t = ()
for i = 1,20000 do
()
end
return () - t
end
function Test4()
local t = ()
local tp = typeof(SkinnedMeshRenderer)
for i = 1,20000 do
local go = ()
go:AddComponent(tp)
local c = go:GetComponent(tp)
eShadows=false
end
return () - t
end
function Test5()
local t = ()
for i = 1,200000 do
local p = osition
--t
end
return () - t
end
function Test6()
local Vector3 = Vector3
local t = ()
for i = 1, 200000 do
local v = (i,i,i)
ize(v)
end
return () - t
end
function Test7()
local Quaternion = Quaternion
local t = ()
for i=1,200000 do
local q1 = (i, i, i)
local q2 = (i * 2, i * 2, i * 2)
(ty, q1, 0.5)
总体效率还是Tolua胜出,其中XLua在Test2中较⽐SLua、Tolua差出不⽌⼀个数量级,主要是因为Tolua和SLua对于Unity的值类型变量
做了lua的实现,这种值类型SLua和Tolua中是⼀个table,⽽在XLua中是⼀个Userdata,所以SLua和Tolua在做Test2的时候并没有跟
Unity交互(从JIT结果也能看出来,JIT不能处理C函数,所以JIT后Test2效果提升明显),⽽XLua需要频繁和Unity交互,效率消耗明
显。对于对象类型的变量,3种lua处理机制是雷同的,只是内部实现细节不⼀样⽽已,细节不再本⽂讨论范围内,从实验数据上来看,还是
Tolua的内部实现更加效率。,这篇⽂章对C#与Lua的交互原来有⾮常详细的说明,虽然插件后续有改进,但是核⼼思想还是不变的。
ILRuntime分析:
数据上来看ILRuntime解释器的效率还是很⾼的并不⽐lua慢太多,但是对于Vector3这种Unity值类型的处理跟lua差距⽐较⼤(主要是因
为SLua和Tolua中的Unity值类型其实就是table,等于没有跟Unity交互)。ILRuntime还是⼀个很有潜⼒的Unity热更解决⽅案的,毕竟
C#配合VS的开发效率还是⽐Lua⾼不少的。其中的JIT部分是Mono层的,跟本⾝的C#代码是没有区别的,不参与对⽐。
Script⾃⾝
Test8Test9Sum
Tolua25442464500
SLua25547665022
XLua31145064817
ILRuntime8527904879900
Tolua(JIT)46371417
SLua(JIT)48414463
XLua(JIT)40469510
ILRuntime(JIT)222313536
function Test8()
local total = 0
local t = ()
for i = 0, 1000000, 1 do
total = total + i - (i/2) * (i + 3) / (i + 5)
end
return () - t
end
function Test9()
local array = {}
for i = 1, 1024 do
array[i] = i
end
local total = 0
local t = ()
for j = 1, 100000 do
for i = 1, 1024 do
total = total + array[i]
end
end
return () - t
end
因为Lua全部使⽤的是LuaJIT2.1.0B2版本,所以其实脚本⾃⾝的效率理论上应该是⼀致的,从数据上看也差不多。实验结果上主要体现了


发布评论