导航

关于SLua的性能问题

Posted on 2019-08-02 10:07  剑孤寒  阅读(678)  评论(0编辑  收藏  举报

最近在使用Slua,

这个玩意号称Fastest lua binding via static code generating,

然而在使用过程中发现效率低得吓人,

同样的功能如果用c++写会比这玩意快15倍,

虽然之前对在Unity里用lua会慢这事已经有心理准备了,

毕竟c#/c互调还是会有些消耗的,

而且Unity在编辑模式只能用debug编译,

速度可能会慢一些,

但是效率能差到这种程度着实出乎我的意料了,

翻了一下它的代码才发现,

这玩意的实现实在是一点都不fast啊。

先说c#导出到lua,最终会用这个函数注册到lua:
static public void pushcsfunction(IntPtr L, LuaCSFunction function)
        {
            LuaDLL.lua_getref(L, get(L).PCallCSFunctionRef);
            LuaDLL.lua_pushcclosure(L, function, 0);
            LuaDLL.lua_call(L, 1, 1);
        }

来看一下PCallCSFunctionRef都干了啥:
local assert = assert
local function check(ok,...)
    assert(ok, ...)
    return ...
end
return function(cs_func)
    return function(...)
        return check(cs_func(...))
    end
end
";

LuaDLL.lua_dostring(L, PCallCSFunction);
PCallCSFunctionRef = LuaDLL.luaL_ref(L, LuaIndexes.LUA_REGISTRYINDEX);

在这里把注册进去的函数包了一层,
所以在lua调一次函数实际上是调了三个函数,
这尼玛哪里fast了(一脸黑线)?
不知道为啥作者不搞成像tolua那样,
如果出错直接代码里报出来就可以了,
完全没必要搞成这样,
试了一下,
把LuaDLL.lua_getref(L, get(L).PCallCSFunctionRef)和LuaDLL.lua_call(L, 1, 1)干掉,
再简单修改一下LuaCodeGen.cs去掉push调用是否成功变量的代码以及去掉一些debug代码,
性能直接提升了差不多40%。




再来看c#调用lua函数,
流程上倒是没啥问题,
只是存在大量从c#调c的代码,
例如:
public bool pcall(int nArgs, int errfunc)
        {

            if (!state.isMainThread())
            {
                Logger.LogError("Can't call lua function in bg thread");
                return false;
            }

            LuaDLL.lua_getref(L, valueref);

            if (!LuaDLL.lua_isfunction(L, -1))
            {
                LuaDLL.lua_pop(L, 1);
                throw new Exception("Call invalid function.");
            }

            LuaDLL.lua_insert(L, -nArgs - 1);
            if (LuaDLL.lua_pcall(L, nArgs, -1, errfunc) != 0)
            {
                LuaDLL.lua_pop(L, 1);
                return false;
            }
            return true;
        }
其实可以把这个流程写在c那边,
只要导出一个函数给c#调就可以了,
完全不用调这么多次,
当调用次数变多时,
这里的开销就非常大了,
这个没有改代码测试了,
不过估计改完之后起码能提升20%~30%的性能吧