做网站如何让用户注册,开发公司成本如何管控,如何通过外链提高网站权重,微信公众平台注册要钱吗写在前面\\xLua是Unity3D下Lua编程解决方案#xff0c;自2016年初推广以来#xff0c;已经应用于十多款腾讯自研游戏#xff0c;因其良好性能、易用性、扩展性而广受好评。现在#xff0c;腾讯已经将xLua开源到GitHub。\\2016年12月末#xff0c;xLua刚刚实现新的突破自2016年初推广以来已经应用于十多款腾讯自研游戏因其良好性能、易用性、扩展性而广受好评。现在腾讯已经将xLua开源到GitHub。\\2016年12月末xLua刚刚实现新的突破全平台支持用Lua修复C#代码bug。\\目前Unity下的Lua热更新方案大多都是要求要热更新的部分一开始就要用Lua语言实现不足之处在于\\接入成本高有的项目已经用C#写完了这时要接入需要把需要热更的地方用Lua重新实现\\t即使一开始就接入了也存在同时用两种语言开发难度较大的问题\\tLua性能不如C#\xLua热补丁技术支持在运行时把一个C#实现函数操作符属性事件或者整个类替换成Lua实现意味着你可以\\平时用C#开发\\t运行也是C#性能秒杀Lua\\t有bug的地方下发个Lua脚本fix了下次整体更新时可以把Lua的实现换回正确的C#实现更新时甚至可以做到不重启游戏\这个新特性iOSAndroidWindowMac都测试通过了目前在做一些易用性优化。\\那么腾讯开源的xLua究竟是怎样的技术它是为何如此设计的更令人关心的是xLua的性能如何带着这些问题InfoQ对其作者进行了采访并将内容整理成文。\\嘉宾简介\\车雄生05年毕业在华为工作了6年跟着先后在两游戏创业公司待了几年15年进入腾讯互娱公共组件中心。目前专注于一些游戏公共组件的开发。\\技术背景\\腾讯自研手游就我了解的项目来说大多数游戏引擎都是Unity3D少数用coco2d。\\xLua这个插件具体用到了哪些游戏中虽说xLua是2015年3月就完成了第一个版本但由于当时项目组热更的意识并没有很普遍需求不是很强烈xLua的开发资源都调到更紧急的项目了。直到15年年底正式集成到我们的apollo手游开发框架才迎来xLua的第一个项目。到目前为止我们已知的应用了xLua的项目有十多个其中不乏一些重量级IP或者按星级标准打造的产品。\\在xLua之前面对iOS无法热更新的问题有用ulua的有用slua的也有项目用自研的脚本语言不过当时用人更新的项目也不多。\\热更新流程\\手游的热更新流程很简单只是启动时检测下是否有新版本文件有的话就下载覆盖老文件然后启动。\\\\下载的文件如果是图片模型这些是没问题的但如果是Unity原生的代码逻辑无论是以前的Mono AOT或者后来的il2cpp都是编译成native codeiOS下是跑不了的。\\解决办法就一个别用native code别用jit解析执行就可以了。包括xLua在内的所有热更新支持方案都是通过“解析执行”来实现代码逻辑热更新。\\来自xLua的 Hello world\\1三行代码跑lua脚本\\一个完整的例子仅需3行代码\\下载xLua后解压到Unity工程Assets目录下建一个MonoBehaviour拖到场景在Start里头加上这么三行\\\XLua.LuaEnv luaenv new XLua.LuaEnv();\luaenv.DoString(\CS.UnityEngine.Debug.Log(hello world)\);\luaenv.Dispose();\\\运行就可以看到Console打印的hello world。\\第一和第三行分别LuaEnv的创建以及销毁所谓LuaEnv可以理解为lua虚拟机往往整个工程一个虚拟机即可\\tDoString里头可以是任意合法的lua代码例子中调用了UnityEngine.Debug.Log接口打印了一个logC#的静态函数在CS下直接可用\2C#调用lua系统函数math.max\\xLua支持把一个Lua函数绑定到C# delegate。\\我们先声明一个delegate并为它加上CSharpCallLua标签\\\[XLua.CSharpCallLua]\public delegate double LuaMax(double a, double b);\\\然后在上面那例子加上这么两行luaenv销毁前\\\var max luaenv.Global.GetInPath(\math.max\);\Debug.Log(\max:\ max(32, 12));\\\就那么简单把lua的math.max绑定到C#的max变量后调用就和一个C#函数调用差不多了而且最最重要的是执行了“XLua/Generate Code”后max(32, 12)调用是不产生C#gc alloc的既优雅又高效更详细的可以看XLua\\Doc下的文档。\\xLua全局观\\1易用性编辑器下无需生成代码支持所有特性\\xLua的易用不仅仅体现在编程还体现在方方面面的细节考虑甚至考虑到团队配合工作流。\\xLua仅有两个菜单选择分别是生成代码和清除生成代码。在菜单之外甚至只需要在build手机版本前执行一下“Generate Code”即可这也有API可集成到项目的自动化打包流程。\\这就是xLua的特色功能之一编辑器下无需生成代码支持所有特性。\\之所以做这个功能是因为有的项目反馈“生成代码”对于策划美术太过遥远教了很久还是老忘还有个大项目反馈说由于代码很多每次生成代码后Unity3D都要转很久。\\2扩展性授之以鱼不如授之以渔\\开发中我们往往要用到很多东西比如用PB和后台交互解析json格式的配置文件等等。虽说我们都可以在C#那找到相应的库然后通过xLua去使用这些库但这效率不高最好能有相应Lua的库。\\不少方案是直接集成一些常用的Lua库但这带来些新问题这些库不一定用到却增大安装包集成的库也不一定符合项目习惯json解析有人喜欢rapidjson有人爱用cjson所谓众口难调对于某些项目这些库还是不够还是得自己去想办法加\\腾讯团队的设计原则是授之以鱼不如授之以渔因此xLua\\提供了接口、教程在不修改xLua代码的情况下开发者可以根据个人喜好加入库\通过cmake实现跨平台编译可以选择伴随xLua一起编译修改一个makefile文件搞定各平台编译。\除了很方便加入第三方Lua插件xLua的生成引擎支持二次开发可以编写生成插件生成自己所需的一些代码以及配置。\3性能的保证\\游戏的性能备受关注因此任何模块的变化都需要尽可能不降低甚至调优游戏整体的性能。xLua设计原则是在保证运行效率的前提下尽量的保证开发效率。\\对于性能这块有几个至关重要的版本\\第一个版本1.0.0在05年3月份发布当时delegateinterface作为最主要的C#访问Lua的设定从接口层面避免了boxing、unboxing、gc alloc这是一个良好的起点。做一个通用组件的都知道接口一开始设计不合理导致的问题很难解决别人已经用了甚至已经养成习惯了很难纠正。ps:说起这习惯有的从别的lua插件转为使用xLua的童鞋一开始习惯用LuaFunction.Call去调用luaxLua也保留了这接口可用于性能要求不高的场合他们后期就痛苦了还得一个个地方的改回来。\\第二个很重要的版本是2.0.006年3月发布这版本主要目标就性能优化因为当时有个对性能要求极其严苛的项目想用lua严苛到什么程度呢他们觉得C#性能都不放心战斗系统打算用C写。那版本我们把虚拟机切换到luajit加入了lazyload技术逐行语句的优化甚至关键地方不用C#提供的容器自己写专用的比Dictionary实测性能高4倍。。。可以认为我们重做了一个xLua。最终他们的选型测试结论是选xLua。\\后来和一些项目的交流发现项目组很关注gc alloc这指标甚至比lua和C#间的互调性能指标还要看重。于是有了2.1.0版本06年7月发布这版本主要目标是gc优化我们重写了反射反射调用的gc减少到原来的几分之一性能提高了3倍左右。我们设计了一个全新的复杂值类型支持方案该方案支持的类型更多只要struct的字段都是值类型即可包括用户自定义的struct别的方案都不支持也更省内存Vector3为例内存占用只有别的方案的30%。但也有劣势的地方比如你调用Vector3上的一些方法会比ulua、slua要差因为后面两个把Vector3用lua重新实现了这类耗时不大的运算相比lua和C#直接的适配成本小太多了直接在lua做更划算不过这差距仅限于那几个ulua、slua完全重新实现的类。\\上面只是三个重大节点我们觉得性能是一个需要持续关注的点平时想到一个好点子就会改改测试下有提升就加入建立性能基线防止某个新功能的加入某个bug的修改把性能给改坏了。\\xLua内置Lua代码profiler支持真机调试。目前lua profiler只是一个小工具所以没有做图形化界面典型的一个报告如下\\\\网上也有类似的工具我们这个的优势是对C#函数的支持以及luajit下更为准确。\\真机调试支持各lua插件都一样就是把ZeroBraneStudio调试需要用到的luasocket库预先编译进去而已没什么值得介绍的地方。\\技术实现的细节\\(1) 泛型\\泛型类型除了运行时动态实例化之外都支持而运行时动态实例化需要jit的支持iOS下行不通。举个例子如果你配了对Dictionary\u0026lt;int, string\u0026gt;生成代码那这个类型是可以用的但如果你新更新的lua代码想用一个Dictionary\u0026lt;int, double\u0026gt;这个类型之前没生成代码而且C#里头也没任何地方使用过这就不支持。静态实例化的泛型其实和非泛型类型处理上没区别。\\(2) 委托事件的封装\\委托封装是根据委托的接口生成一段操作lua栈的代码作为委托的实现。举个例子就很好懂了。比如对于委托delegate double Add(double a, double b)我们生成如下代码\\\public double SystemDouble(double a, double b)\{\ RealStatePtr L luaEnv.L;\ int err_func LuaAPI.load_error_func(L, errorFuncRef);\ \ LuaAPI.lua_getref(L, luaReference);\ \ LuaAPI.lua_pushnumber(L, a);\ LuaAPI.lua_pushnumber(L, b);\ \ int __gen_error LuaAPI.lua_pcall(L, 2, 1, err_func);\ if (__gen_error ! 0)\ luaEnv.ThrowExceptionFromError(err_func - 1);\ \ double __gen_ret LuaAPI.lua_tonumber(L, err_func 1);\ LuaAPI.lua_settop(L, err_func - 1);\ return __gen_ret;\}\\\这代码把调用转给lua函数调用委托就是调用这函数。\\其它方案都有delegate的支持一般仅用于在lua侧主动传递/设置一个lua函数到C#而xLua支持更为完整比如\\支持C#主动用delegate来引用一个lua函数。用delegate代替类似object[] Call(params object[] args)的接口调用lua最大的好处是可以避免值类型传递时的boxing/unboxing还有参数数组返回值数组的gc alloc\支持返回delegate的delegate可对应到lua的高阶函数\作为这技术的一个延伸xLua支持用一个c# interface引用一个lua table这个特性和一些IOC框架配合可以实现C#和Lua间无感知模块间都通过interface耦合然后由框架去组装。\\(3) 无缝支持生成代码及反射\\生成代码固然重要已然是各大主流方案的标配。\\反射有的方案明确不支持但从项目的反馈来说也是至关重要的有的项目代码很多已经接近苹果的80M Text段的限制对他们来说代码量大小关乎到能否发布反射方式性能不如生成代码但对安装包影响小。\\这的无缝有两个含义\\两者在支持的特性以及特性的使用方式都是一致的两者方式间切换业务逻辑代码不用修改改改配置就可以了\\t两者无缝配合比如一个继承链上任意一个类都可以选择生成代码或者反射比如子类选择生成代码父类由于不常用选择了反射还是可以在子类对象上调用父类的方法\对于il2cpp的strippingxLua也考虑到了只要你对一个类配置了ReflectionUse会自动生成Unity的link.xml配置文件将该类型列为不剪裁。\\其他Lua插件一览\\在xLua之外还有其他的Lua插件如 uLua、SLua、C#light等。\\(1) ulua应用项目是最多的由于开源得早名气也最大这是它很大的优势。腾讯也有项目用ulua反馈比较多的问题是它版本的前后兼容问题\\ulua最早是一个叫LuaInterface开源库的Unity移植在2015年初换成cs2lua又在2016年初换成tolua c#只所以说“换”是因为这从API角度看可认为三个不同的产品它们间很难升级而且是每换一次之前的版本就彻底不维护了这给项目带来很大的困扰。\ulua的第一个版本纯反射并不实用已经淡出市场现存应用用后两个版本居多。cstolua版本接口比较混乱它保留了第一版ulua接口之余搞了一套新接口这两套接口之间并不正交也不是后者完全替代前者让人有点无所适从。到了tolua c#版本这问题解决了但同时也把反射特性老接口给废了。不过总体来说ulua在向好的方向走。\(2) slua代码质量比cstolua好很多很多人当时选slua的理由部分支持反射。性能按我们的测试用例整体比tolua c#略低另外代码质量对比tolua c#已经形成不了明显优势。\\(3) C#light个人觉得主要有两个不足\\按其实现原理来说性能不会靠谱到不了手机上实用的地步\由于不完整支持C#本质上只是另一种叫C#light的语言C# like名字倒很贴切这两者代码配合起来也复杂甚至它能做到比C#和lua配合更复杂些\事实也证明了C# light基本淡出市场可以忽略不计了。\\(4) LSharp是C# light作者的后续作品倒是可以期盼些从il层面执行这两个问题有望改善可惜后面没了下文不维护了。\\相比之下腾讯在设计xLua时实现的功能更全这“全”体现在C#的特性支持得更全些lua虚拟机版本支持更全更易用些比如编辑器下不用生成代码另外性能也不比它们差。\\说到功能更全可能有人抱怨并没有pbjsonsqlite等等功能。其实稍熟悉lua的人都知道那只是把一些现成lua扩展编译进去而已算不上是它做了这些功能。预集成好处是方便坏处是没选择的余地用不上的东西会占空间用得上的东西也不一定是你喜欢的库。\\xLua的lua库基于cmake编译要加这些库门槛很低有教程改一个Makefile搞定各平台编译。在C#测也提供了api来初始化这些库。总而言之xLua的原则是授之以渔。\\xLua的灵感来源\\xLua立项当初考察了当时能找到的所有方案并分析各方案优劣定出第一个版本的特性大体是基于NLua基础上加上代码生成。介绍下NLuaNLua的作者就是LuaInterface的作者NLua可以认为是LuaInterface的升级版而前面也说了第一版uLua是LuaInterface的Unity移植版本也不能算原创。\\因为是“站在”生成代码当时有看过cstolua的实现那时还没挂ulua的牌觉得它通过硬编码字符串拼接的方式维护性不太好就用模版来做。感觉这步是走对了后续生成代码调整起来比较简单这对性能调优很有好处。\\经过十多个版本的迭代优化现在NLua的影子比较淡了NLua仅支持反射而xLua的反射在2.1.0版本已经完全重写就剩下C#引用类型对象在lua的表达的思路没变。\\此外遇到需要调整较大的bug我们也会先看同类插件是不是已经解决了对比他们的修改方案和我们的选更适合的。\\xLua背后的研发与团队\\xLua目前迭代了十多个版本从第一个项目开始平均一个月一个版本。\\研发团队人员目前有一个全职开发。测试使用的是腾讯互娱的公有资源很规范有一套不断补充的功能自动化用例性能测试也建立了基线确保不会因为功能迭代而影响性能。腾讯互娱有专门的客户端兼容性测试实验室至少中版本号以上的变动我们会提交给他们针对top 100的机型进行兼容性测试。\\至于lualuajit的更新跟进先说luajit吧luajit变动不大我第一次用luajit是11年那时支持到lua5.1现在也还是lua5.1中间只是一些bug的修复性能优化或者新平台支持等我们要做事情不多。而lua中版本间差别还是蛮大的但中版本变动并不频繁从5.1到5.2用了6年从5.2到5.3用了3年5.3是2015年初发布的我个人觉得到下一次中版本变动会很久不亚于甚至大于5.1到5.2的时间跨度5.2个人认为只是一个过渡版本。\\小版本一般改改bug等稳定后直接升级就可以了不需要做很多事情目前xLua的lua版本用的是lua的最新版本5.3.3。\\聊聊C#谈谈Lua\\C#在开发效率和运行效率平衡得很好语言特性也比较全个人觉得是很优秀的一门语言。在Unity3D上的缺憾主要是其mono版本太低一些很古老的bug比如著名的foreach性能问题很多个版本都没解决新的特性比如await又不支持。\\另外在手机平台iOS不允许应用下载native code运行jit刚好把mono应用的热更新给堵死了要是mono虚拟机能够做到像luajit那样jit走不通就用interpret模式其实就没lua或者其它热更新方案什么事了。\\而lua被称为游戏脚本之王在游戏领域应用比较广泛它设计之初就考虑到嵌入式领域比如相对它提供的特性来说它体积非常小启动一个vm占资源也不多性能也是脚本里头的佼佼者。\\lua相对C#而言首先是它支持解析执行进而支持热更新。而免编译对开发效率提升也是蛮大的特别是较大的项目。\\lua的动态类型有利有弊好的是没有编译期的类型检查快速开发比较有优势特别在需求三天两头就变的游戏领域。缺点是要做出健壮的软件得有大量的测试来保证还有由于要做运行期检查性能会比静态类型语言低。\\lua的一大特色是语言级的协程coroutine的支持比Unity3D基于generator模拟的协程要好很多对于复杂异步业务逻辑编写很有帮助xLua的配套例子有范例ps一下Unity3D的mono版本升级到支持await的话是更理想的异步方案。\\至于C#和lua间如何配合可能每个人都有不同的看法但至少有一点是确定的需求变更大预计很可能需要热更的地方用lua。当然也可以尝试最新的开发模式全C#开发lua fix bug。\\写在最后\\xLua应该还有不足我们会在发现的第一时间去修改。腾讯xLua团队极度欢迎大家在发现不足之后提出反馈。\\