背景是这样的,我最近在监控哪些代码会比较消耗cpu,监控到场景服务启动没多久,一帧运行了2秒钟左右,我本能的觉得这里有问题,通过监控的信息,断定是在场景服务向战斗服务发送数据的时候,占用了过多的cpu时间,编译skynet的时候,没有注意警告,导致没有看到数据打包和解包的调试信息,这里多花了点时间进行分析和定位,经过对消息投递,调用函数时对元表__index函数的调用,数据的解包和打包的调试和分析,最终锁定在数据的打包和解包占用了过多的cpu时间,数据打包和解包的时候分别花了300ms左右,开了很多战斗服务。
知道了是因为数据的打包和解包占用了过多的cpu时间,结合之前对lua虚拟机之间共享数据的实现机制的理解,以及我对lua源码的理解,我想另辟蹊径。我的想法是定义一个新的消息类型(lua、response分别是一种消息类型,每种类型有自己的打包和解包的方法),先将调用的函数和参数打包成一个table,设置这个table为只读(通过设置元表),发送消息的服务缓存这个table,并且这个table是缓存在注册表中(其实放在某个lua文件的table里也可以),然后将可查到这个table的lua_State的地址和查找前面table的索引打包,总共12字节,在解包的地方根据这12字节逆向操作,就能拿到要执行的函数和参数,执行完函数,把这个table的deleted设置为true,发送方每间隔1秒钟会检测有没有table的deleted为true,如果有,就赋值为nil,解除引用关系,lua的gc最终会释放内存。经历了打包发送服务的主线程(lua_State),新建一个协程,由数据发送服务方和数据接收服务方共同确定一个key,来新建一个独立的lua_State(要设置一个元表的__gc,在表被删除的时候,删除这里的lua_State),确定下来,用最后这种方案是安全可靠的,经过测试,这里的消耗小于1ms,我比较满意。
这个小功能经过多轮迭代,中间也产生了很多思考,尤其是对接口的抽象和封装深有体会,如果已有的代码在一个服务向另一个服务发送消息时,有一个通用的接口,这里我只要改一下这个接口的实现,就能实现全部替换。
skynet的服务间共享table的实现
最新推荐文章于 2024-06-03 14:04:50 发布