从最初决定使用Golang开发游戏服务器(参考这里),到服务器基本成型,经过了两个多礼拜的时间。这里记录一下感想和心得。具体Golang的使用经验将来有时间会再开篇文章来写。
两个礼拜的时间,完成了Golang的入门,服务器框架设计,功能的完整移植,从我个人角度来说,要给Golang和我自己100个赞。
最初我选定Golang就是考虑到它有以下优点;
1、静态编译型语言。这个是我最看重的,不选择skynet(c+lua)和KBEngine(c++ python)有很大一个原因是动态脚本语言维护逻辑复杂了维护起来非常困难。 静态语言基本编译通过后就没有太大问题了,剩下的就是思考不周导致的bug。
2、堪比python的开发效率。 不选java很大的一个原因是这个。 我不需要最优方案,也不需要最稳妥的方案,只需要一个合适的方案。
3、并发模型,可以轻易利用起多核。 不选Node.js的原因是callback还没有真正完善的解决方案
4、有现成的开源服务器。即便不说有成功案例,至少是有可行的案例
5、优异的跨平台能力。 我想部署KBEngine到linux,结果python编译了半天都没成功。(顺便吐槽下linux,不同发行版本,软件源中的软件名不一样,操作命令和习惯也不一样,简直是作)
6、部署方便,只要把执行文件拷贝一下就可以了,没有太多的依赖或者动态库。同样参考上一条。
7、支持protobuf、mongoDB。KBEngine中我一直想做这个修改,不过改动太大,完全Hold不住。这个不算特别的优点,因为很多其他的方案也都支持,只不过恰好不谋而合而已。
而最后的结果也基本满意。
Golang并不是一个完美的语言,甚至从c++系转过来的人会感觉很多不爽,尤其是诡异的变量命名规则。
不过Golang是一个解决实际问题的工业级语言。可能语法上面看各种粗糙,但是习惯后使用起来非常顺手。它在解决网络大并发问题的基础上(go 协程),同时兼顾了静态语言的优势和堪比Python的开发效率,从这点上来说再怎么称赞它都不为过。 在这个巨大优势的前提下,其他的一些不爽都是可以接受和忽略的。 其他的如Rust、Scala等,虽然语法、语义更棒,但是并不能解决我碰到的实际问题(并不是说它不能解决任何问题),只有Golang将这三者完美的融合在一起。
关于Golang的入门,我总结了三点需要注意的:
1、包和GOPATH。
Golang并没有项目工程文件,它通过自动解析包引用构建整个项目。一个文件夹对应一个包,一个包对应一个模块,模块内可以定义各种结构和函数。 而main包就是程序的主入口,它包含一个main函数。
GOPATH是go查找包的路径,我现在设置两个路径,一个是当前项目路径,一个是公共包的路径。go在编译的时候会依次查找对应路径下有没有这个包。 go build和go install可以构建程序。 一个项目中可以包含多个main包,也就对应多个进程。比如我的服务器项目中就对应login gate game三个进程。
理解了包和GOPATH就可以非常方便的维护整个项目
2、指针和内存
Golang中有指针的概念(这点我并不喜欢,感觉还不如像c#或者java一样直接干掉指针,只有对象的概念)。但是指针的功能极度弱化,你可以像正常对象调用一样使用指针,不能操作指针的内存,也不能对指针进行自增等操作。 指针的意义就是传递参数是防止值传递,也就说Golang的指针就相当于c++中的引用。
同样的,你并不能控制一个对象是在堆上创建还是在栈上创建。Golang中new(TestStruct)和&TestStruct{}是完全等价的写法。只不过后一个写法可以同时进行初始化操作。 创建出的内存都是交给GC来进行管理的。 所以返回局部对象的指针是完全合法和正确的。
3、Struct和interface{}
type User Struct {
name string
}
func (self *User) login(account string, token string) {
}
通过这样的写法就定义了一个结构User,并且这个结构有一个成员函数login。 通过包、Struct、包函数、成员函数这四个元素就可以轻松的处理对象和框架设计。
接口是Golang中非常强大的语法特性,一个Struct只要实现了一个接口(函数名和参数相同)就可以当做这个接口来使用。 通过接口,大大减轻了设计负担,不需要设计模式,一样可以写出高质量的优雅的代码