Lua 不是 C++
http://blog.codingnow.com/2008/08/lua_is_not_c_plus_plus.html
嗯,首先,此贴不是牢骚帖。
话题从最近私人的一点工作开始。应 dingdang 的建议,我最近在帮 大唐无双 做一些程序上的工作。接手做这件事情,是因为这个内部被我们称作 dt2 的游戏 engine 关系重大。公司有至少四个项目在使用(另外三个暂处于研发期,尚未公布)。
dt2 用了大量的 lua 代码构建系统,但从系统设计上,沿袭了老的大唐的许多代码。原来的大唐是用 C++ 构建的,为了利用上这些代码(虽然我觉得这种复用非常无意义,但是其中原因复杂,就不展开谈了),dt2 engine 的开发人员做了一套非常复杂的中间层,把 lua 和 C++ 几乎无缝的联系在了一起。
从表征上看,可以完全不修改 C++ 代码,只额外加上一些东西,便可以在 lua 中得到一个类对象,从语法上相当接近的使用 C++ 的类,并可以对其继承,用 lua 重载其虚函数。甚至可以实现多重继承。
由于项目组隔的比较远,所以直到最近一个月,我才拿到这套东西的文档和源码。我的直觉告诉我,这属于过厚的粘合层,是绝对需要抛弃的。如果不是无双内测初期频频的出现 bug ,可能不会有太多人赞同我这个观点。但事实上,即使这个粘合层实现的绝无问题,完全正确的使用它也几乎是不可能的。这么厚的粘合层很难做到 robust 。
这段时间,在开发维护人员的不懈努力(不包括我,在为这个项目修 bug 的工作上,我只是一打酱油的)下,主要的 bug 也修的差不多了,但是做一些适度的改造也必须开展。跟 engine 的前开发人员聊过,我很能理解这个东西被做成这个样子,以及为什么做这样一个东西的必然性:对 lua 的不熟悉,以及迫切的需要复用 C++ 代码。但是我依然想说,解决问题之道在于,先仔细考虑问题存不存在。不做是最好的做法。
表面上看起来,这个粘合层是设计的是很精妙的,它隐藏了 lua 虚拟机的细节。C++ 程序员在写代码的时候,并不需要实际上也的确是,不知道 lua 的存在。而 lua 程序也不需要关心那个类是用 C++ 实现的。在 lua 中,可以按照 C++ 的对象模型继续对类进行继承扩展。一切都展现的完美无缺。
C++ 的代码从某种程度上也显得非常有水准,template 的灵活使用,可以在可能存在的领域重复利用发挥出功效,大量使用的 stl 容器以及智能指针保证了底层领域的健壮。
如果不是这个粘合层的对象生命期管理出了一点设计上的小问题。在 C++ 的引用计数和 lua 的 gc 管理之间有点搅和不清,我想,这个东西可能就一直用下去了。我也不会被派来对这些代码做 code review 。
没错,代码的 bug 最终都可以改过来,这个设计点上的错误也可以想办法用比较小的代价纠正。但是,仔细的考虑一下,整件事情应该去做吗?在 lua 里实现一个 C++ 的面向对象的对象模型?
面向对象不是 C++ 语言向我们展示的那些东西。这不是 C++ 语言的错,因为 C++ 只是在用它的方式去表达而已。我们可以去寻求 lua 的表达方式,正像 ROR 追寻 ruby 的表达方式一样。
诚然,培养新的语言的程序员,比把一门语言模拟成另一种要困难的多。如果我们用写 C++ 程序的思考方式去写 lua 程序,那么当我们决定把游戏用 lua 重新实现一次。除了性能,我们还会失去很多。
前段时间去广州出差,和西游组的同事吃饭。据说最近一年来,他们改进了大话和梦幻的服务器设计,把处理连接的部分独立出来放到单独的进程中 ,使服务器性能大大提高。梦幻西游的服务器,已经可以做到单台机器支持一万人同时在线。
可惜的是,大话 3 的服务器,依然徘徊在单机三千人左右。表面上最大的区别是,梦幻西游的游戏逻辑是用一种类 C 的脚本语言 LPC 写的,而大话3 则是用的 lua 。
刨除大话 3 更为复杂的逻辑处理的因素,追根到底是,lua 的表达能力更强,导致了程序员用更 C++ 的方式去用 lua 。而原来的 LPC 的代码更接近 C 一些。
不是说 C++ 比 C 慢,对于编译语言来说 C++ 甚至比 C 的执行性能更高。但是对于解释型的动态语言。那种看起来更 C++ 的风格会拖垮运行性能许多。对于开发人员来说 lua 5 以后加入的 meta table 是个好东西,但是任何强大的特性都可能被滥用。有幸 lua 还是门简洁的语言,如果有一天 ruby 在游戏开发圈子里流行起来,我都不敢想会发生怎样的事情 ;)
对于那些新接触 lua 的 C/C++ 程序员来说,我的第一条建议通常是:看看 lisp/scheme 吧,可能 lua 的血统里,scheme 的成分比 C 更多一些。要不玩一下 Haskell ,增进对函数式编程的了解。C++ 借助 template 是可以玩玩函数式编程,但很少有人真的去用。进入 lua 的领域后,你得正正经经的理解一下了。
关于 dt2 engine ,这几天我为之做的最多的事情是重新实现了一个 timer tick 的系统,这个东西很早以前就做过,也有现成的代码。不过 200 行。
但是,重新实现一个的意义在于:把这个子模块剥离出来,绕过原来的厚粘合层。而不是先前的那种设计:在 C++ 里实现一个 CTick 类,然后从 lua 中继承它,再注册回 C++ 中的 CTickMgr 。
可能下一步还会协助开发组的同事把连接管理分离出来,并改进数据库的访问。
最后友情做一个广告:大唐无双 这个游戏还是不错的。美术和玩法方面都有了长足的进步。技术问题我相信在大家的努力下都会慢慢的解决。网易的开发团队还是很强的。
Lua 不是 C++的更多相关文章
- lua执行字节码的过程介绍
前面一篇文章中介绍了lua给下面代码生成最终的字节码的整个过程,这次我们来看看lua vm执行这些字节码的过程. foo = "bar" local a, b = "a& ...
- lua 学习笔记(1)
一.lua函数赋值与函数调用 在lua中函数名也是作为一种变量出现的,即函数和所有其他值一样都是匿名的,当要使用某个函数时,需要将该函数赋值给一个变量,这样在函数块的其他地方就可以通过 ...
- 在redis中使用lua脚本让你的灵活性提高5个逼格
在redis的官网上洋洋洒洒的大概提供了200多个命令,貌似看起来很多,但是这些都是别人预先给你定义好的,但你却不能按照自己的意图进行定制, 所以是不是感觉自己还是有一种被束缚的感觉,有这个感觉就对了 ...
- 使用Nginx+Lua代理Hadoop HA
一.Hadoop HA的Web页面访问 Hadoop开启HA后,会同时存在两个Master组件提供服务,其中正在使用的组件称为Active,另一个作为备份称为Standby,例如HDFS的NameNo ...
- 打印Lua的Table对象
小伙伴们再也不用为打印lua的Table对象而苦恼了, 本人曾也苦恼过,哈哈 不过今天刚完成了这个东西, 以前在网上搜过打印table的脚本,但是都感觉很不理想,于是,自己造轮子了~ 打印的效果,自己 ...
- lua解析赋值类型代码的过程
我们来看看lua vm在解析下面源码并生成bytecode时的整个过程: foo = "bar" local a, b = "a", "b" ...
- 怎么调试lua性能
怎么调试lua性能 我们的游戏使用的是Cocos2dx-lua 3.9的项目,最近发现我们的游戏.运行比较缓慢.想做一次性能优化了.其实主要分为GPU.CPU的分别优化.GPU部分的优化.网上有很多优 ...
- Lua 安全调用 metatable 的简单应用
事情的经过 我们的项目中存在好几个战斗界面,不过界面中的内容略有不同.跟同事出去吃饭的时候,他问我.我们现在的战斗界面.有很多是重复的,但是也有偶尔几个地方不太一样.我在战斗过程中驱动这些界面的时候. ...
- 让Lua自己把文件夹下面的所有文件自动加载起来吧
没有想到我也做了一回标题党.其实这里边说的自动还是有夸大其词的部分.其实只是指定文件夹,然后根据指定文件夹数据,加载目录下边的内容而已. 怎么来进行Lua文件的加载 一般情况下,相关的功能需要给他创建 ...
- 让Lua支持Linq吧
第一次接触Linq是在使用C#的时候,这种语法,在处理列表数据非常方便.如果想了解Linq的更多内容可以百度一下Linq,不过你不了解也没关系,让我在Lua中给你展示一下Linq的魅力.简单点说,Li ...
随机推荐
- [GUIDE] How to Setup Ubuntu 16.04 LTS Xenial Xerus for Compiling Android ROMs
With a new version of Ubuntu comes an update to my guide for setting up a build environment to compi ...
- Django-admin导出到表格
class AdminReport(admin.ModelAdmin): actions = ["saveexecl"] # 自定义的action(导出到excel表格) list ...
- 关于 angular cookie 设置的坑
初识Angular,才知道掉进了这么一个各种大坑的坑. 先说下对于$cookie.put 这几个方法,只有1.4以上版本才可以用,其余低于版本请使用 $cookieStore: 下面举例下使用方法: ...
- openwrt 修改 banner
http://www.network-science.de/ascii/ rectangles 风格
- CentOS 7 yum安装路径查询方法
先执行下面的命令,查看所有的已安装软件名称. rpm -qa 然后执行 rpm -ql 软件名称 就可以显示软件的安装路径.
- EasyDarwin手机直播是如何实现的快速显示视频的方法
前言 经常有人提到最近比较火的映客直播.花椒直播这种,是如何做到在打开手机直播中的某一个主播房间后,立即就能显示出主播视频,非常非常快,而且延时也比较小,是怎么做到的? 其实,这并不是什么高深的技术, ...
- mybatis入门(五)
根据用户名称模糊查询用户信息 @Test public void findUserByNameTest() throws IOException { // 通过工厂得到SqlSession SqlSe ...
- Spring 配置JNDI数据源
1.Spring 提供的JNDI调用类. 2.使用weblogic进行部署项目,所以使用WebLogicNativeJdbcExtrator类进行配置. 3.配置完数据源后配置sessionFacto ...
- volley get post json imagerequest imageloader networkimageview 加载网络本地图片
官方网站 https://www.androidhive.info/2014/05/android-working-with-volley-library-1/ private void initL ...
- 1022. Fib数列
https://acm.sjtu.edu.cn/OnlineJudge/problem/1022 Description 定义Fib数列:1,1,2,3,5,8,13,…1,1,2,3,5,8,13, ...