xml version="1.0" encoding="utf-8" standalone="yes"12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/category/21050.html谈论群:309800774 知乎重视:http://zhihu.com/people/sunicdavy 开源项目:https://github.com/davyxuzh-cnWed, 29 Aug 2018 22:18:36 GMTWed, 29 Aug 2018 22:18:36 GMT6012bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2018/08/29/215887.html战魂小筑战魂小筑Wed, 29 Aug 2018 03:16:00 GMThttp://www.fometaux.com/sunicdavy/archive/2018/08/29/215887.htmlhttp://www.fometaux.com/sunicdavy/comments/215887.htmlhttp://www.fometaux.com/sunicdavy/archive/2018/08/29/215887.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/215887.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/215887.html为了编写依据cellnet的新一代游戏服务器结构,最近深入研讨微服务,ServiceMesh等概念。研讨进程中对Web和游戏两种服务器架构规划有一些心得,编写并记录下来。(下文中,Game表明游戏服务器,Web表明Web服务器) ``
状况缓存
所谓状况缓存,便是在内存而非专业数据缓存服务器(如redis)中保存和处理逻辑数据,手动编写此进程较为繁琐可是功率较高,但随着状况逻辑杂乱性和并发、扩容问题提出,状况同步会变得越来越杂乱。
Game:
强交互性的服务器类型需求在服务器做缓存,逻辑编写也较为简略,无需处理业务并发问题。例如:组队,匹配,战役逻辑。服务器不能随意重启。
弱交互性的服务器类型可合作redis做成无状况服务器,例如:养成,技能晋级,收取物品等。服务器随时支撑重启。
游戏服务器为了进步功用,前期一切服务器都是运用状况缓存写法编写,特别是MMORPG这类强交互的游戏服务器尤为严峻。
Web:
均为无状况服务器,弱交互。运用业务办法处理并发逻辑,例如:买卖,下单等。
推送,独自发送
这儿说到的所谓推送,独自发送是与RPC差异的通讯办法。RPC要求恳求有必要有回应。而推送独自发送则更像是告知和播送,无需意图方回来任何音讯。
Game:
找到服务器的Session,直接Send
经过中转服务器,或称为中心服务器进行注册/播送
客户端的model数据需求更新时,服务器会主动推送音讯。
游戏服务器没有严厉的RPC规划需求,推送和独自发送较Web服务器更多。并且游戏服务器多运用长衔接,所以主动推送也比Web服务器来的便利一些。
Web:
将推送做成专有的服务,并做排队和并发处理。
可用性
听说过游戏停服更新,支付宝服务器在刷二维码时停服了可必定被骂惨吧。Web对服务器高可用性要求很高,游戏尽管也重视服务器安稳性和可用性,可是由于版别迭代更新频频,停服更新反而能取得玩家承受。
Game:
游戏对可用性要求不高。
游戏大版别更新时需求停服更新。支撑热更新技能的服务器(例如Erlang,Skynet)仅运用热更新修正bug,很少直接更新新版别。
不是一切的游戏服务器支撑动态增加服务器。
Web:
极高的可用性,服务不允许停服更新,运用蓝绿及灰度办法更新服务器。
随时能够横向扩展服务器,进步服务器容量和承载。
衔接及传输
均运用TCP传输协议,游戏服务器重视功用,自有协议及二进制协议运用较多。
Web重视兼容和接口友爱,运用JSON格局较多。
Game:
运用长衔接,需求从逻辑层保护衔接状况及处理服务器不在线状况
运用自有封包格局,大部分运用protobuf或二进制流格局。
Web:
微服务大部分运用短衔接,grpc支撑http2长衔接
运用json编码便利调试和版别兼容。
流量约束
人数多了,任何服务器都扛不住,流量约束和登入约束能有用保护服务器安稳。
Game:
单服有人数约束,能够经过GM后台设置挡墙,超越无法进入
Web:
限流器中间件,能够准确到服务操控流量
断流,防止雪崩
Game:
游戏没有,也不需求这种概念,游戏恳求不会忽然升高,即使有,也经过GM后台人为操控
Web:
断流器中间件
服务发现
怎么找到服务器地址。
服务有改变时,经过Watch系统告知订阅者更新本地缓存
服务器没有改变时,运用本地缓存找到服务地址
Game:
游戏服务器相互依靠复用只在很小的规模内,因而无需在不同言语不同进程服务间取得地址,大部分在装备文件中填写各服务的IP及地址即可相互拜访。
前期游戏自己编写服务器状况及地址发现服务。
有用redis做服务发现
Web:
运用服务发现系统,分布式布置。无需依靠装备文件
网关需求
Game:
网关处理客户端上下线告知,心跳,保持衔接,转发,播送上下行封包
Web:
依据恳求地址路由,无上下线概念,无心跳。播送经过音讯推送系统完结
由于笔者从事游戏职业,对Web服务器概念在逐步了解中,若有过错和缺乏请各位大佬指出。
自己新书《Go言语从入门到进阶实战》,生动的言语,比方带有各种彩蛋,轻松了解Go言语特性,更有cellnet结构剖析解密
https://search.jd.com/Search?keyword=go%E8%AF%AD%E8%A8%80%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E8%BF%9B%E9%98%B6%E5%AE%9E%E6%88%98&enc=utf-8&suggest=1.def.0.V02&wq=Go%E8%AF%AD%E8%A8%80%E4%BB%8E&pvid=145d55a92cab4b07b71326f8beb1700b


战魂小筑 2018-08-29 11:16 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2017/07/06/215057.html战魂小筑战魂小筑Thu, 06 Jul 2017 04:47:00 GMThttp://www.fometaux.com/sunicdavy/archive/2017/07/06/215057.htmlhttp://www.fometaux.com/sunicdavy/comments/215057.htmlhttp://www.fometaux.com/sunicdavy/archive/2017/07/06/215057.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/215057.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/215057.html本文首要研讨游戏服务器带状况的热更新需求 http的无状况热更新需求现已有老练计划, 故不在本文描绘规模

底子概念

  • Golang的热更新选用什么机制?

    运用go1.8供给的plugin包机制完成

  • plugin包自身规划的意图是热更新么?

    plugin包其实仅仅支撑将代码别离编译为多个动态库,动态加载后运转 并不能彻底支撑相似C/12bet的动态库办法处理代码

  • 带状况的进程热更新的底子概念及规模是什么?

    数据部分(model)不更新, 只更新逻辑部分(函数)

  • 表格和装备更新算热更新么?

    算, 但不是本文描绘规模

  • 热更新能在windows上运用么?

    不支撑

代码及结构

  • 我能将原本一个exe的代码编译为so供给给plugin运用么?

    能够, 可是有必要仍然保存main包作为插件进口, 并在main包内增加供给给plugin调用进口.

  • 假如动态库中没有main包, 编译出的so能用么?

    不能, 包有必要包含main, 不然输出的是.a的文件, plugin包加载会报错

  • 动态库中, 非main包的的代码修正能做热更新么?

    不能!(溃散了吧, 我提了一个issue: https://github.com/golang/go/issues/20554)

    假如的确做了修正, 底层会报错: plugin was built with a different version of package

    处理办法: 修正plugin包底层完成偏从头编译 翻开runtime/plugin.go, 注释以下代码 for _, pkghash := range md.pkghashes { if pkghash.linktimehash != *pkghash.runtimehash { return "", nil, pkghash.modulename } } 履行/usr/local/go/run.bash 重编译+测验

  • 代码中哪些能够被更新? 办法能够被更新么? 闭包呢?

    只能更新具有静态地址的结构.例如: 包等级函数(相似于静态函数)

    例如: svc_0.so里有一个Foo函数, svc_1.so修正了Foo函数完成, 热更新可完成

    闭包=函数+捕获变量, 实践上是一个动态结构, 没有静态地址, 无法被更新

    各种包等级变量, 结构体变量, 结构体办法, 局部变量均不能被热更新, 可是变量值不会被影响

    新增结构能够被运转

  • 运用结构体办法调用了包等级函数, 包等级函数能被更新么?

    能够, 尽管办法不能被更新, 但办法被调用的包等级函数的地址是固定的, 所以能够被热更新

  • init包初始化函数能用么? 能被热更新么?

    官方这样描绘:

    When a plugin is first opened, the init functions of all packages not already part of the program are called. The main function is not run. A plugin is only initialized once, and cannot be closed

    插件第一次被翻开时, 其相关的, 没有成为程序的一部分的一切的包的init函数将被调用. 插件的main函数不会被调用. 插件只会被初始化一次, 不能被封闭

    因而, 需求手动将init函数改成自己的函数, 一致在so的main包里调用

编译

  • 怎么编译取得plugin包支撑的动态库

    SVCNAME=$1 SVCVER=$2 TIMESTAMP=`date '+%Y%m%d_%H%M%S'` go build -v -buildmode=plugin --ldflags="-pluginpath=${SVCNAME}_${TIMESTAMP}" -o ${SVCNAME}_${SVCVER}.so ${SVCNAME}

    -buildmode=plugin是重要参数

    --ldflags里的-pluginpath的作用是: 每次编译的内部辨认途径都是不同的, 防止重复加载的正告

    参阅: https://github.com/golang/go/issues/19004



战魂小筑 2017-07-06 12:47 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2017/04/20/214874.html战魂小筑战魂小筑Thu, 20 Apr 2017 04:52:00 GMThttp://www.fometaux.com/sunicdavy/archive/2017/04/20/214874.htmlhttp://www.fometaux.com/sunicdavy/comments/214874.htmlhttp://www.fometaux.com/sunicdavy/archive/2017/04/20/214874.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/214874.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/214874.html运用Visual Studio Code调试Golang工程

关键字

  • 最简略的调试攻略
  • 多项目调试, 适用个人开发和项目开发
  • 无需修正系统环境变量

预备VSCode

在官网下载最新版的VSCode:

https://code.visualstudio.com/

装置Golang插件

  • 翻开扩展面板

    VSCode->检查->扩展

  • 找到Go插件 在查找框里输入Go, 找到第二行写有 Rich Go language support for Visual Studio Code的插件, 点击装置

    留意不是排名最高的

  • 重启修正器

装备发动项

  • 翻开调试面板

    VSCode->检查->调试

  • 增加调试方针

    在"没有调试"的下拉框中点击"增加装备.."

  • 增加方针调试装备

    比方:

    {
        "version": "0.2.0",
        "configurations": [
            {
                "name": "Launch",
                "type": "go",
                "request": "launch",
                "mode": "debug",
                "remotePath": "",
                "port": 2345,
                "host": "127.0.0.1",
                "program": "${fileDirname}",
                "env": {
                    "GOPATH":"D:/Develop/vscodegolang"
                },
                "args": [],
                "showLog": true
            }
        ]
    }

其间: "port", "host"都是go插件主动生成的

"env"为设置环境变量, 设置为你的工程目录就能够(包含bin, src的文件夹)

预备调试插件

此刻找到main.go按F5, 会报错提示:

Failded to continue:"Cannot find Delve debugger. Install from https://github.com/derekparker/delve & ensure it is in your "GOPATH/bin" or "PATH"

咱们运用go指令行编译调试器

go get github.com/derekparker/delve/cmd/dlv

将dlv调试器放在GOPATH(工程目录)的bin目录下

开端调试

选中要调试的main.go, 点击F5, 既能够开端调试

调试快捷键和Visual Studio系共同

  • F9 切换断点
  • F10 Step over
  • F11 Step in
  • Shift+F11 Step out

留意点

  • 某些结构体成员无法直接显现时, 能够直接选中变量名, 增加到监督, 或许右键点击: "调试:求值"

多项目调试

在launch.json中能够增加多组调试进口, 经过调试面板中选中对应的装备敞开不同方针的调试

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "client",
            "type": "go",
            "request": "launch",
            "mode": "debug",
            "remotePath": "",
            "port": 2345,
            "host": "127.0.0.1",
            "program": "${fileDirname}",
            "env": {
                "GOPATH":"D:/Develop/vscodegolang"
            },
            "args": [],
            "showLog": true
        },

        {
            "name": "server",
            "type": "go",
            "request": "launch",
            "mode": "debug",
            "remotePath": "",
            "port": 2345,
            "host": "127.0.0.1",
            "program": "${workspaceRoot}/src/server",
            "env": {
                "GOPATH":"D:/Develop/vscodegolang"
            },
            "args": [],
            "showLog": true
        }
    ]
}

"program"中的"${fileDirname}"是以当时选中文件作为发动点

更主张运用"program"的"${workspaceRoot}", 以包名作为发动点的办法进行装备

参阅链接

https://code.visualstudio.com/Docs/editor/debugging



战魂小筑 2017-04-20 12:52 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/12/01/214457.html战魂小筑战魂小筑Thu, 01 Dec 2016 02:45:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/12/01/214457.htmlhttp://www.fometaux.com/sunicdavy/comments/214457.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/12/01/214457.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/214457.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/214457.htmlGolang中没有规划结构函数. 取而代之的, 规划Golang的大师期望你用一般函数去完成结构的使命. 
一向仅仅觉得这仅仅体现Golang这门新言语的精简规划之道, 直到自己完成编译器后才发现结构函数的规划自身是值得商讨的

咱们先看下结构函数的规矩

结构函数调用规矩

结构参数量: 0表明没有结构函数, 1表明有结构函数0个参数

本类结构父类结构处理办法
00不处理
10调本类ctor
01调父类ctor
11调本类ctor, 本类ctor调父类ctor
21调本类ctor, 本类ctor调父类ctor
12报错, 手动调父类ctor
22报错, 手动调父类ctor

一般函数重载规矩

实践只用考虑最典型的一种行为: 实例化子类, 转为父类调用办法, 这个时分

假如办法是override, 调用的是子类

假如办法是virutal或许不指明, 调用的是父类

整个重载进程, 子类必定不会隐式调用父类的行为

需求结构函数么?

结构函数的长处

  • 自身归于一种特别的成员函数
  • 编译器帮你主动传导调用父级

结构函数的缺陷

  • 隐式的调用规矩
  • 尽管归于成员函数, 可是与其他成员函数调用规矩彻底不同, 需求特别回忆
  • 带参数的结构函数, 在父类参数多于子类时, 需求引证杂乱语法来完成父级结构调用

其实咱们对初始化函数的需求只要1条: 自界说

所以, 能够了解Golang不参加结构函数的规划是正确的 
即: 简略, 明晰, 有规则



战魂小筑 2016-12-01 10:45 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/11/02/214375.html战魂小筑战魂小筑Wed, 02 Nov 2016 03:09:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/11/02/214375.htmlhttp://www.fometaux.com/sunicdavy/comments/214375.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/11/02/214375.html#Feedback1http://www.fometaux.com/sunicdavy/comments/commentRss/214375.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/214375.htmlappend, map, len不是关键字

他们其实仍是类库功用, 都在buildin包里的, 系统默许给你做了个

  1. import(
  2. . "buildin"
  3. )

将buildin的包内容都映射到大局罢了, 其实你也能够用自己的包这么做

打印的另一种写法

想跟脚本相同调试打印数据么?

  1. println("hello world")

无需包含任何包, 由于它在buildin包里

iota不是黑科技

这是在buildin包里的界说

  1. // iota is a predeclared identifier representing the untyped integer ordinal
  2. // number of the current const specification in a (usually parenthesized)
  3. // const declaration. It is zero-indexed.
  4. const iota = 0 // Untyped int.

其实go是有泛型概念的

想想map和数组的界说 
仅仅泛型没有开放给用户用罢了(只许XX放火,不许XX点灯)

map是支撑多个key的, 并且很便利

还在为多个key转id的杂乱算法而头疼么?

  1. type myKey struct{
  2. number int
  3. str string
  4. }
  5. func main(){
  6. t := map[ myKey] int {
  7. myKey{ 2, "world"}: 1,
  8. }
  9. fmt.Println(t[myKey{2, "world"}])
  10. }
  11. 输出: 1

枚举是能够转成string的

默许界说一个枚举

  1. type MyConst int
  2. const (
  3. MyConst_A MyConst = iota
  4. MyConst_B MyConst = iota
  5. )
  6. func main(){
  7. fmt.Println(MyConst_A)
  8. }

输出: 0 
假如咱们想主动化输出MyConst_A字符串时 
就需求运用golang的一个东西链:golang.org/x/tools/cmd/stringer 
将其下载, 编译成可履行东西后, 对代码进行生成 
生成的代码会多出一个xx_string.go 
里边便是枚举的String()string 函数

暂时转化一个接口并调用的办法

  1. type love struct{
  2. }
  3. func (self*love)foo(){
  4. fmt.Println("love")
  5. }
  6. func main(){
  7. var chaos interface{} = new(love)
  8. chaos.(interface{
  9. foo()
  10. }).foo()
  11. }

Golang的receiver实践上便是this的变种完成

  1. func( self*MyStruct) foo( p int ){
  2. }

写不惯receiver的写法? 假如这样改下呢?

  1. func foo( self *MyStruct, p int ){
  2. }

所以为什么说Golang仍是一个C言语嘛

关于内存分配…

  • new 传入Type类型, 回来*Type类型
  • make 能够在分配数组时设置预分配巨细, new不能够
  • make 能分配数组,map, 但不能分配结构体和原始类型
  • new 能分配数组, map, 结构体和原始类型等的一切类型
  • &Type等效于new
  • 切片不需求分配内存(make,new), 直接声明就能够了…

Golang的反射无法经过一个类型名, 创立其实例

C#有Assembly概念, 能够在一个Assembly里查找, 创立实例

Golang是静态类型言语, 假如需求, 只能注册你需求创立的结构体, 然后将注册好的map用于创立

Golang能够替换Python来进行杂乱的东西流程处理

假如你需求跨渠道的东西流程处理, 对Python不了解, 能够运用

  1. go run yourcode.go 参数1 参数2

办法来进行东西处理 
觉得慢, 能够编译成可履行文件

这样做的长处: 假如有些类库自身便是go写的, Python想运用是很费事的, 而Golang来写则垂手可得

比方: 经过go的protobuf库, 对一些文件进行处理

Golang能够主动持有办法的接收者实例

  1. type myType struct{
  2. }
  3. func (self*myType) foo( p int){
  4. fmt.Println("hello", p )
  5. }
  6. func main(){
  7. var callback func( int )
  8. ins := new(myType)
  9. callback = ins.foo
  10. callback( 100 )
  11. }

做过lua的12bet代码绑定的童鞋都清楚: lua只支撑外部静态或许大局函数调用 
假如要进行12bet类成员函数调用时, 要自己处理this和成员函数 
这种技巧由于早上编译器的虚表不同渠道完成细节纷歧致需求专门处理 
后边跨渠道虚表一致后, 类成员函数的调用写法也是很厌恶杂乱的 
可是Golang的小白式用法, 直接吊打12bet, 乃至C#杂乱的delegate

LiteIDE篇: 多开秘籍

  • 找到 菜单->检查->选项->通用->存储->存储设置到本地ini文件

  • 封闭LiteIDE

  • 仿制LiteIDE整个目录, 命名文件夹为你的工程名

  • 每个工程地点的LiteIDE的装备将是独立的, 不会相互搅扰

LiteIDE篇: 测验程序也是能够调试的

别以为程序必定要是main开端的才能够调试

Golang的测验程序尽管都是一个个Test最初的函数,但履行go test时, 仍是有main进口

在LiteIDE中, 能够在 调试->开端调试测验程序里进行测验程序调试

LiteIDE篇: 在Windows上能够输出linux可履行文件

go的东西链默许支撑穿插编译 
在LiteIDE中, 能够经过切换输出渠道, 输出不同渠道的可履行文件



战魂小筑 2016-11-02 11:09 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/09/03/214254.html战魂小筑战魂小筑Sat, 03 Sep 2016 10:12:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/09/03/214254.htmlhttp://www.fometaux.com/sunicdavy/comments/214254.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/09/03/214254.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/214254.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/214254.html

Google官方为Golang的调试比方默许运用了gdb

可是, 运用gdb调试go程序会遇到goroutine的各类问题, 由于gdb不明白go

因而, 这儿运用delve黑科技来进行Golang的程序调试

纯指令行调试办法在网上很简略查找到, 本文首要以LiteIDE来进行程序调试

封闭编译器优化

正常go build/install出的go程序是彻底优化过的, 强行运用调试器挂接调试时, 某些local变量/lamda表达式捕获的变量会直接进入寄存器, 无法运用调试器检查

删掉一切的pkg, 为build或install参数参加封闭编译器优化的参数 -gcflags "-N -l"

例如:

  1. go install -gcflags "-N -l" svc\gamesvc

delve调试器装置办法

LiteIDE自带了gdb, 可是没有delve调试器, 需求自行装置, 指令如下

  1. go get github.com/derekparker/delve/cmd/dlv

delve调试器会被放到你的GOPATH/bin下

LiteIDE中的delve调试器装备

挑选调试器

在LiteIDE菜单中挑选 调试->debugger/delve

delve环境变量设置

这个时分, LiteIDE仍然找不到delve, 由于它不在环境变量PATH中, 这儿无需修正环境变量, 只需求LiteIDE的环境装备

在LiteIDE菜单中挑选 检查->修正当时环境, 在弹出的文档中修正

  1. PATH=c:\mingw32\bin;%GOROOT%\bin;%PATH%;c:\your\path\to\delve

去掉PATH前的注释#, 在%PATH%增加分号, 然后和你到delve调试器的途径

开端调试

挑选你的工程, 点击F5, 进入调试形式

调试器显现变量值

LiteIDE运用delve调试时, 无法在 变量 监督等窗口中正确捕捉delve调试回来数据(由于格局太杂乱了…)

不要紧, 咱们运用指令行合作显现即可

LiteIDE操控台或调试输出窗口在delve调试时, 实践上是一个规范指令行 
指令如下

  • p 变量名能够检查变量值

  • locals检查局部变量

  • ls可检查当时文件

  • stack检查栈

  • help能够检查各种协助

调试外部程序

假如你的程序是外部程序, 或许运用go install装置到GOPATH/bin目录的程序, 那么运用delve调试器发动程序时, 可能会碰到发动途径过错的问题

运用LiteIDE菜单 调试->调试其他运用程序… 填入你要调试程序的途径以及作业目录, 能够处理这个问题



战魂小筑 2016-09-03 18:12 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/08/12/214152.html战魂小筑战魂小筑Fri, 12 Aug 2016 07:26:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/08/12/214152.htmlhttp://www.fometaux.com/sunicdavy/comments/214152.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/08/12/214152.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/214152.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/214152.html测验用例

咱们对Golang的结构体变量赋值, 以及单参数函数调用进行反射和native操作的测验

 

package main

 

import (

"reflect"

"testing"

)

 

type data struct {

Hp int

}

 

const AssignTimes = 100000000

 

func TestNativeAssign(t *testing.T) {

 

v := data{Hp: 2}

 

for i := 0; i < AssignTimes; i++ {

v.Hp = 3

}

 

}

 

func TestReflectAssign(t *testing.T) {

 

v := data{Hp: 2}

 

vv := reflect.ValueOf(&v).Elem()

 

f := vv.FieldByName("Hp")

 

for i := 0; i < AssignTimes; i++ {

 

f.SetInt(3)

}

 

}

 

func TestReflectFindFieldAndAssign(t *testing.T) {

 

v := data{Hp: 2}

 

vv := reflect.ValueOf(&v).Elem()

 

for i := 0; i < AssignTimes; i++ {

 

vv.FieldByName("Hp").SetInt(3)

}

 

}

 

func foo(v int) {

 

}

 

const CallTimes = 100000000

 

func TestNativeCall(t *testing.T) {

for i := 0; i < CallTimes; i++ {

 

foo(i)

}

}

 

func TestReflectCall(t *testing.T) {

 

v := reflect.ValueOf(foo)

 

for i := 0; i < CallTimes; i++ {

 

v.Call([]reflect.Value{reflect.ValueOf(2)})

}

}

功用测验数据

=== RUN TestNativeAssign
— PASS: TestNativeAssign (0.03s)
=== RUN TestReflectAssign
— PASS: TestReflectAssign (0.41s)
=== RUN TestReflectFindFieldAndAssign
— PASS: TestReflectFindFieldAndAssign (9.86s)
=== RUN TestNativeCall
— PASS: TestNativeCall (0.03s)
=== RUN TestReflectCall
— PASS: TestReflectCall (21.46s)

测验评测

  • 在结构体变量赋值测验用例中, 咱们发现TestReflectFindFieldAndAssign赋值分外的耗时. 剖析功用点在FieldByName这个函数上, 咱们查了下底层怎么完成的:

// FieldByName returns the struct field with the given name

// and a boolean to indicate if the field was found.

func (t *structType) FieldByName(name string) (f StructField, present bool) {

// Quick check for top-level name, or struct without anonymous fields.

hasAnon := false

if name != "" {

for i := range t.fields {

tf := &t.fields[i]

if tf.name == nil {

hasAnon = true

continue

}

if *tf.name == name {

return t.Field(i), true

}

}

}

if !hasAnon {

return

}

return t.FieldByNameFunc(func(s string) bool { return s == name })

}

各位看官有必要吐槽用for来遍历获取数据, 但冷静下来剖析. 这样做无可厚非.
试想假如reflect包在咱们运用ValueOf时运用map缓冲好一个结构体一切字段的拜访数据后, 必定拜访指定字段速度会很快
可是, 以空间换速度的需求其实最多满意了1%的需求.
相同的比方是图形API里拜访Shader变量的办法, 总是默许运用字符串获取, 速度很慢. 当你想快速拜访时, 请提早按需缓存字段
那么, Golang运用的也是这样的思路. 尽管暴力了一点, 可是能够让程序跑对, 功用优化的东西放在之后来做, 缓冲下就能够处理

  • 在调用测验用例中, 毫无悬念的, 调用速度很慢
    因而, 咱们在平常运用反射时, 尽量倾向于反射变量缓冲存鄙人的变量赋值或许获取
    而调用的需求尽量削减, 假如有goroutine存在的状况下, 则不用太多忧虑.


战魂小筑 2016-08-12 15:26 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/01/25/212739.html战魂小筑战魂小筑Mon, 25 Jan 2016 06:23:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/01/25/212739.htmlhttp://www.fometaux.com/sunicdavy/comments/212739.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/01/25/212739.html#Feedback0http://www.fometaux.com/sunicdavy/comments/commentRss/212739.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/212739.html本文编写时, Google 官方的 protobuf 版别是3.0.0beta

下面介绍下proto3的一些细节改变

Proto3的语法改变

语法符号

这个版别的protoc的protobuf编译器现已能够支撑proto2语法和proto3的语法

假如你的proto文件没有增加syntax阐明的话, 用这个版别的编译器会报错, 提示你默许proto2支撑, 请增加语法符号

syntax = "proto2";

 

optional不需求了

只保存repeated符号数组类型, optional和required都被去掉了

实践运用证明, required的规划的确是蛋疼, 12bet的调试版会弹出assert,release版和optional也没啥差异

map支撑

map编写格局为

map<key_type, value_type> map_field = N;
例如:
map<string, Project> projects = 3;
代码生成承认支撑map, 这关于许多言语来说又能够偷闲了

字段default符号不能运用了

坐落proto2语法的字段number后的[default=XX]

这个东西不能用了, 理由是:

关于同一段序列化后的数据, 假如序列化端的default和反序列化端的default描绘不相同会导致终究成果彻底不共同

即: 同一个数据两个成果, 这是不行猜测的成果, 因而干掉这个特性

不过自己觉得, 关于游戏来说, 这个功用自身能够紧缩许多数据,尽管会有风险

 

枚举默许值必定是0

proto2里的默许值是枚举的第一个value对应的值, 不用定为0

proto3在你界说value时, 强制要求第一个值有必要为0

这个修正为防止风险仍是有协助的

泛型描绘支撑

any类型, 能够代表任何类型, 能够先读进来, 再进行解析, 没具体用, 脚步跨大了怕扯到蛋

支撑json序列化

这个极好, json再次被同化了

增加了多种言语支撑

js, objc, ruby, C#等等

可是, C#版别的根底runtime库是用C# 6.0的语法写的,这关于Unity mono祖传2.0来说, 的确扯到蛋了,没法用

Protobuf现在运用CMAKE做装备系统

编译起来略微费事, 还要下个被墙掉的cmake…

 

 

第三方库里关于proto3的改变

Golang的官方protobuf支撑: https://github.com/golang/protobuf

生成代码中的结构体字段类型改变

关于proto2的文件, 生成的go代码中的结构体仍然运用类型指针作为默许存储, 兼容老的系统

关于proto3的文件, 生成的go代码中的结构体直接运用字段作为默许存储, 不再运用GetXXX来作为字段值拜访, 赋值时也无需运用proto.类型() 函数进行指针类型字段值创立.

这个调整很是便利, 但丢掉了optional判别功用, 对应12bet里便是hasXXX的功用, 不过好歹这个逻辑现在用的不多了

这个修正大约也是合作json序列化来做的, go默许的json序列化时, 无法运用proto2生成的结构体的, 由于都是指针,无法赋值..

 

新版protoc-gen-go的插件会生成descriptor的紧缩数据

新插件会给每次生成的文件增加这样一段代码

var fileDescriptor0 = []byte{
    // 220 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x64, 0x8f, 0xcd, 0x4e, 0xc5, 0x20,
    0x10, 0x85, 0x53, 0xbd, 0x35, 0x32, 0xb7, 0xdd, 0x4c, 0x5c, 0xb0, 0x70, 0x71, 0xd3, 0xb8, 0x70,
    0x75, 0x17, 0xfa, 0x04, 0xc6, 0xd8, 0xb8, 0x50, 0x63, 0xa8, 0x2f, 0x80, 0xed, 0x44, 0x89, 0x28,
    0x04, 0xc6, 0xbf, 0x47, 0xf1, 0x6d, 0x95, 0x49, 0x8d, 0x4d, 0x5c, 0x01, 0xdf, 0x39, 0x7c, 0x30,
    0x00, 0x1c, 0x82, 0xdf, 0xc6, 0x14, 0x38, 0xe0, 0xaa, 0xec, 0xbb, 0x37, 0x68, 0x2e, 0x3e, 0x62,
    0x48, 0x7c, 0x49, 0x76, 0xa2, 0x84, 0x47, 0xd0, 0xde, 0x96, 0xf8, 0xee, 0x33, 0xd2, 0x8d, 0x7d,
    0x26, 0x5d, 0x6d, 0xaa, 0x63, 0x65, 0xda, 0xb8, 0x84, 0xd8, 0x41, 0x63, 0xc2, 0x7b, 0xef, 0xc8,
    0x4f, 0x52, 0xda, 0x91, 0x52, 0x93, 0x16, 0x0c, 0x0f, 0x41, 0x89, 0xa9, 0x77, 0x9e, 0xf4, 0xae,
    0x14, 0x54, 0xfc, 0x05, 0xdd, 0x57, 0x05, 0x4a, 0xba, 0xd7, 0xc4, 0x16, 0xb7, 0x80, 0x03, 0x27,
    0xf7, 0xf2, 0x70, 0x72, 0xe5, 0x32, 0x0f, 0xd1, 0x3b, 0xa6, 0x34, 0x5b, 0x31, 0xff, 0x4b, 0x70,
    0x03, 0x6b, 0x43, 0x91, 0x2c, 0x9f, 0x3f, 0xd2, 0xf8, 0x24, 0xf6, 0x7d, 0xb3, 0x4e, 0x7f, 0x08,
    0x0f, 0xa0, 0x3e, 0xf3, 0xce, 0x66, 0xbd, 0x12, 0x49, 0x6d, 0xcb, 0xa1, 0x4c, 0x37, 0xbf, 0xf3,
    0xb3, 0xbc, 0x8e, 0xac, 0x6b, 0xb9, 0xd9, 0xe6, 0x25, 0xbc, 0xdf, 0x93, 0x6f, 0x9e, 0x7e, 0x07,
    0x00, 0x00, 0xff, 0xff, 0x0c, 0x9f, 0x10, 0xa8, 0x2e, 0x01, 0x00, 0x00,
}

关于meta信息的提取仍是很便利的

可是

关于多个文件的生成, 这样做十分的费事, 由于这个字段会重复导致编译过错

许多人在论坛里吐槽, 官方给出的处理办法是, 运用protoc一次性传入一个package下的一切的proto直接生成一个go

而不是现在的一个proto一个go

生成代码会主动注册到大局, 并能够便利的查询

从前这个代码需求自己来做, 现在官方供给了支撑, 很是便利

可是, 为什么不支撑遍历… 残念啊, 又要自己着手了



战魂小筑 2016-01-25 14:23 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/01/25/212738.html战魂小筑战魂小筑Mon, 25 Jan 2016 06:00:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/01/25/212738.htmlhttp://www.fometaux.com/sunicdavy/comments/212738.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/01/25/212738.html#Feedback2http://www.fometaux.com/sunicdavy/comments/commentRss/212738.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/212738.html项目地址:

https://github.com/davyxu/tabtoy



战魂小筑 2016-01-25 14:00 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2016/01/05/212611.html战魂小筑战魂小筑Tue, 05 Jan 2016 08:51:00 GMThttp://www.fometaux.com/sunicdavy/archive/2016/01/05/212611.htmlhttp://www.fometaux.com/sunicdavy/comments/212611.htmlhttp://www.fometaux.com/sunicdavy/archive/2016/01/05/212611.html#Feedback10http://www.fometaux.com/sunicdavy/comments/commentRss/212611.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/212611.html以下比较的根底都是依据一种编程言语+必定的第三方或许自己编写的网络库和底层进行的,Skynet略微特别,但整体比较适宜放到比较中来

C#

开发功率:Windows下能够经过VisualStudio进行开发,其他渠道能够运用MonoDevelop,十分便利

运转功率:JIT的功用优化比较到位,能习惯90%功用环境

布置快捷性:能够经过穿插编译生成其他渠道的可履行文件,经过mono运转可履行文件

调试快捷性:VisualStudio和MonoDevelop调试均很便利, 还可长途调试

上手度:对C系言语了解的几天就可上手

热更新:能够经过DLL办法进行

Web对接:可做,代码比较烦琐

溃散处理:可经过try catch捕获过错

网络库编写难度:一般,需留意gc问题

第三方网络库及结构数量:一般

 

Golang

开发功率:高

运转功率:并发上十分有优势,对CPU利用率比较高,原生运转无虚拟机

布置快捷性:一次编译处处运转,无任何运转库依靠

调试快捷性:实践操作中,单线程挂接调试器可行, 但变量显现不正确,开发期底子选用日志办法进行查错

上手度:言语简略,特性少, 新手1周能奉献代码

热更新:无法进行热更新,言语无法编译为DLL,也不支撑DLL加载(linux渠道的.so加载忽略不计)

Web对接:十分便利, 代码精简

溃散处理:溃散后以指令行办法打印出栈,程序内能够捕获任何溃散过错并持续运转

网络库编写难度:简略,比C socket更简略

第三方网络库及结构数量:偏少

 

Skynet(lua+C)

开发功率:依据动态言语的开发初度写比较快,后期保护和重构会消耗必定的时刻在查错上

运转功率:依据lua jit的运转功率仍是能承受的

布置快捷性:便利, 只要底层修正需求从头编译, 大部分时刻只用更新lua文件

调试快捷性:不是很便利,依据日志办法进行查错

上手度:lua言语特性有部分和C系言语有必定差异,依据Actor模型的思想学习,习惯需求消耗必定的时刻

热更新:相似于Erlang,可准确到函数级的热更新

Web对接:有一些http支撑,经过社区渐渐进行完善

溃散处理:lua天然生成能够捕获过错

网络库编写难度:自带,无需编写

第三方网络库及结构数量:经过社区渐渐完善

 

12bet

开发功率:编译慢,文件多,通用库少

运转功率:native速度标杆

布置快捷性:编写各类的make门槛较高

调试快捷性:可经过VisualStudio进行Windows渠道调试

上手度:2~3年阅历的熟手仍然会写出溃散和走漏代码

热更新:可经过DLL进行

Web对接:代码烦琐,第三方库少

溃散处理:Windows下可运用SEH捕获段反常,其他渠道只能经过溃散后进行coredump剖析,容错十分差

网络库编写难度:依据asio编写较为简略,但整体看来难度不低

第三方网络库及结构数量:较多

 

以下是得分

image

 

从发文时的项目对这些言语运用率来说,Java,Erlang,12bet编写的服务器较多,Golang,JavaScript,C#是第二队伍,Skynet由于上手不是很简略,所以仅有两位数的团队在运用,但整体体现仍是比较超卓的

关于老团队, 12bet的服务器东西链和结构现已相对老练, 彻底没必要替换新言语, 仅仅在对接sdk感觉困难时,能够测验Golang这些对web有优势的言语进行混合言语开发

关于新团队,开发功率,上手度和布置功率是优先挑选的,C#,Golang,JavaScript这些新式言语会让你事半功倍

关于大规模无需选服的服务器, Skynet的actor模型对扩展会比较简略

关于大公司,好项目,上线后需求经过热更新进行bug修补的,C#,12bet,Erlang会是首选

 

但总的一点, 仍是依据团队了解度来挑选言语,轻率的运用新言语的风险也是很大的

战魂小筑 2016-01-05 16:51 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2015/10/16/212026.html战魂小筑战魂小筑Fri, 16 Oct 2015 03:44:00 GMThttp://www.fometaux.com/sunicdavy/archive/2015/10/16/212026.htmlhttp://www.fometaux.com/sunicdavy/comments/212026.htmlhttp://www.fometaux.com/sunicdavy/archive/2015/10/16/212026.html#Feedback6http://www.fometaux.com/sunicdavy/comments/commentRss/212026.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/212026.html简略,便利,高效的Go言语的游戏服务器结构

func server() {
 
    pipe := cellnet.NewEventPipe()
 
    evq := socket.NewAcceptor(pipe).Start("127.0.0.1:7234")
 
    socket.RegisterSessionMessage(evq, coredef.TestEchoACK{}, func(content interface{}, ses cellnet.Session) {
        msg := content.(*coredef.TestEchoACK)
 
        log.Println("server recv:", msg.String())
 
        ses.Send(&coredef.TestEchoACK{
            Content: proto.String(msg.String()),
        })
 
    })
 
    pipe.Start()
 
}
 
func client() {
 
    pipe := cellnet.NewEventPipe()
 
    evq := socket.NewConnector(pipe).Start("127.0.0.1:7234")
 
    socket.RegisterSessionMessage(evq, coredef.TestEchoACK{}, func(content interface{}, ses cellnet.Session) {
        msg := content.(*coredef.TestEchoACK)
 
        log.Println("client recv:", msg.String())
 
    })
 
    socket.RegisterSessionMessage(evq, coredef.SessionConnected{}, func(content interface{}, ses cellnet.Session) {
 
        ses.Send(&coredef.TestEchoACK{
            Content: proto.String("hello"),
        })
 
    })
 
    pipe.Start()
}

 

项目地址: https://github.com/davyxu/cellnet



战魂小筑 2015-10-16 11:44 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2015/09/23/211895.html战魂小筑战魂小筑Wed, 23 Sep 2015 10:31:00 GMThttp://www.fometaux.com/sunicdavy/archive/2015/09/23/211895.htmlhttp://www.fometaux.com/sunicdavy/comments/211895.htmlhttp://www.fometaux.com/sunicdavy/archive/2015/09/23/211895.html#Feedback2http://www.fometaux.com/sunicdavy/comments/commentRss/211895.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/211895.html看C#比方

            Action[] a = new Action[3];
 
            for (int i = 0; i < 3; i++)
            {
                a[i] = ( ) => { Console.WriteLine(i); };
            }
 
            for (int i = 0; i < 3; i++){
                a[i]();
            }

C#打印成果为3 3 3

 

Golang的比方

    a := make([]func(), 3 )
    
    for i := 0; i < 3; i++ {
        
        a[i]= func( ){
            
            fmt.Println(i)
            
        }    
    
    }
    
    for _, s := range a {
        s()
    }

Golang打印成果为3 3 3

 

最终是Lua的比方

a = {}
 
for i = 1, 3 do
 
    table.insert( a, function()
        print(i)
    end
    )
 
end
 
 
for _, v in ipairs(a) do
    v()
end

Lua打印成果为1 2 3

 

差异在于, C#和Golang将变量捕获到闭包内时, 均运用引证办法, 即当最终开端调用运用变量时, 由于变量现已完毕循环, 所以是终究值

可是Lua捕获办法是值捕获, 因而比较简略了解, 是多少便是多少



战魂小筑 2015-09-23 18:31 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2015/09/09/211784.html战魂小筑战魂小筑Wed, 09 Sep 2015 11:06:00 GMThttp://www.fometaux.com/sunicdavy/archive/2015/09/09/211784.htmlhttp://www.fometaux.com/sunicdavy/comments/211784.htmlhttp://www.fometaux.com/sunicdavy/archive/2015/09/09/211784.html#Feedback6http://www.fometaux.com/sunicdavy/comments/commentRss/211784.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/211784.html多线程+同步堵塞模型

在咱们的游戏项目中运用的golang服务器开发办法如下

1.多线程逻辑

2.同步堵塞. 也便是说, 每个人一个线程(goroutine), io线程=逻辑线程

这种办法的长处:

1. 同步堵塞办法与人的思想办法类同

2. 逻辑处理功用有必定进步

在大规模运用这种形式编写逻辑后, 咱们发现了这种形式只要1个缺陷: 编写者需求处理多线程联系

但这自身的确直接丧命的, 回想12bet年代, 多线程处理时, 调试重现的困难… 脑补现象太惨不敢直视

单线程+异步多进程模型

在12bet年代, 我从前编写过一套asio的12bet服务器结构. 选用io多线程, 逻辑单线程, 依靠着12bet高功用的优势, 让开发快捷简略且无需关怀线程问题.

那么到了golang年代, 为什么不能试下单线程异步多进程办法来编写逻辑?

与多线程同步堵塞比照后, 咱们发现, 两者优缺陷互补. 那这就回到了范畴选型问题了. 关于游戏服务器需求的上手简略, 开发快捷, 压力下降(非MMO)这些特色来说, 单线程异步多进程再适宜不过了

那么, 咱们在用golang编写单线程异步多进程服务器应该留意哪些点呢?

1. socket处理彻底封装, 只经过channel抛出到逻辑线程排队处理

2. 数据库, rpc及其他io处理, 一概改为异步回调形式, 不运用同步接口

3. 玩家存盘提交数据能够考虑仿制并提交到存盘线程办法, 进步功用.

4. 选用多进程架构, 比方设网关进程, 把io压力涣散到进程中

5. 逻辑编写中, 不允许运用go开线程及channel, 有需求进步功用部分需求独自编写

 

Actor模型的痛

cellnet在开发时原本考虑运用actor模型来进一步简化多线程逻辑的费事, 阅历了一段时刻的原型开发后, 发现了一些问题, 列举如下:

1. golang的强类型不合适actor模型这种常常需求动态生成各类音讯的模型, 但skynet(C+lua)/erlang就有天然生成优势

2. actor模型自身不是全能的, 不能处理一切需求, 特别是游戏

3. actor模型了解到运用有必定的难度. 自身还需求树立结构, 上手杂乱

总归, 看过一些erlang及skynet的用例, 没有运用的很纯粹且老练的成功actor模型事例, 从传统socket服务器结构跨越到actor模型会扯到蛋, 因而, 后期cellnet会考虑回归到老练的socket服务器结构. 把架构做到简略上手, 高扩展上.



战魂小筑 2015-09-09 19:06 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2015/07/21/211321.html战魂小筑战魂小筑Tue, 21 Jul 2015 02:30:00 GMThttp://www.fometaux.com/sunicdavy/archive/2015/07/21/211321.htmlhttp://www.fometaux.com/sunicdavy/comments/211321.htmlhttp://www.fometaux.com/sunicdavy/archive/2015/07/21/211321.html#Feedback8http://www.fometaux.com/sunicdavy/comments/commentRss/211321.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/211321.html最近参加了一个大服务器架构谈论活动, 记录下心得

概述

游戏客户端选用Cocos2dx-Lua的纯Lua编写逻辑, 服务器选用Golang作为开发言语

游戏类型相似于COC,因而无需选服. 需求运用大服务器架构进行处理

数据库

选用Mongodb做耐久存储, redis做跨服通讯数据交换

运用UCloud的云技能, 省去了烦人的运维作业

通讯及协议

客户端和服务器通讯运用HTTP短衔接, 依据json的数据封包协议

服务器间许多运用Golang自带的json+rpc进行通讯

服务器类型

服务器类型大致分为逻辑服务器,战役服务器, 中心服务器

逻辑服务器

逻辑服务器担任日常逻辑及公共逻辑处理(老友, 公会)

1个逻辑服务器对应一个区, n个区均运用Ucloud云Mongodb进行数据存储

战役服务器

战役服务器是一个集群, 集群会回来一个负载最低的服务器回来运用

战役服务器经过cgo技能与客户端12bet/lua的战役逻辑进行逻辑复用, 在此技能上进行

战役逻辑的校验

中心服务器

客户端登陆前, 在中心服务器这儿取得可登陆的逻辑服务器地址, 一起做一个负载均衡

短衔接

点评

由于操作系统的技能趋于安稳, 一起, 手游的弱交互型导致的游戏架构趋于简略. 因而网络负载不再是游戏服务器技能的瓶颈. 从阅历看来, 游戏服务器技能, 更重要的是仍是看数据库的选型及处理办法. 

尽管Mongodb的功用上不如内存数据库. 可是从存储安全性上要比个人树立的内存数据库简略, 安全

外加上云技能的引证, 功用的瓶颈和运维的技能杂乱度方便的处理

Redis用于跨服数据交互那是再好不过的数据中介了, 确保速度和安稳性, 必定不是造轮子能比较的

短衔接在手游上处理起来比长衔接简略一些, 无需做断线重连. 服务器的底层也是由Golang的结构库确保质量的. 因而负载毫无问题. 服务器对内及对外均运用json进行数据交换, 简化了协议处理. 也便利了调试

json rpc的功用损耗关于整个逻辑的处理来说均能够忽略不计



战魂小筑 2015-07-21 10:30 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2015/06/04/210823.html战魂小筑战魂小筑Thu, 04 Jun 2015 09:19:00 GMThttp://www.fometaux.com/sunicdavy/archive/2015/06/04/210823.htmlhttp://www.fometaux.com/sunicdavy/comments/210823.htmlhttp://www.fometaux.com/sunicdavy/archive/2015/06/04/210823.html#Feedback1http://www.fometaux.com/sunicdavy/comments/commentRss/210823.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/210823.html满打满算, 从老友引荐Golang至发文时, 运用Golang现已有1年多了. 这种时刻关于C/12bet Java这些老者来说, 简直是菜鸟等级的阅历

但作为新生代言语的特色便是实战. Golang这一年里, 现已为项目供给了安稳的服务器和强壮的扩展才能, 与客户端的Unity3D里的C#相同, 都是强壮, 极致开发功率代表的优异开发言语.

用处篇

Golang究竟拿来做啥? 我需求么?

高效(功用,开发)的服务器言语. 包含Web, 游戏, App

编写桌面级UI暂不是很合适

我需求把现在的12bet, Python, Erlang等服务器改成Golang么?

功用有瓶颈, 开发功率低, 有钱有时刻的话, 彻底能够

 

点评篇

听过太多的人对Golang的点评, 大约分为这么几类:

C/12bet功用党

此类党员对任何事物都寻求极致的 功用. 还好Golang是直接生成native code, 不然会被批的遍体鳞伤. 可是由于Golang底层为并发和开发功率而做出的一些系统, 相似于GC, 调度器和分配器等, 会在言语层上丢失许多功用. 因而C/12bet党仍是有理由批Golang功用低下

Erlang并发党

作为电信级元老, Erlang的模型和架构名副其实, OTP扩展性超级强. 完美的Actor模型也让逻辑编写比OO愈加直观

CSP与Actor差异仅仅仅仅在channel的归属规模罢了, 但这点细微差别却对两种言语的开发变的截然不同

Golang在并发模型上挑选了CSP, 便是考虑把架构的规划留给运用者. 像C#相同树立一个类库的国际, 而不是MFC相同的结构国际. 让开发更自在

Erlang的Actor也没错. 让开发更直观, 让溃散提早来到, 赶快处理

Rust党

Rust在发文时现已发布了1.0. 这让R粉振奋的络绎于各大技能论坛和谈论群

但Rust的理念在我看来有点偏执了, 必定要把各种过错在编译期露出出来, 所以造出了许多不需求的类型和概念, 连言语都比C言语更符号话

大白话说来, 有点编程阅历的人看到JavaScript彻底看得懂, 但看Rust却像天书

比照一起期的TypeScript, Dart, Swift. Rust便是有点那么别出心裁

该党党员常常性的用各种特性比照Golang, 寻求单特性的优异.

但其实, Golang自身是一门完好哲学. 许多言语特性相互之间有相关. 有规划不妥的当地, 当然更多的是完好系统. 不求和其他言语比

只寻求处理问题的速度

自界说党

云风看过Golang后, 由于该言语自身便是强化版的C, 因而颇受云风喜爱. 但在一堆点评后, 云风仍是决断挑选了C+lua的组合写出的Skynet

尽管不知道原因, 但我猜的话, 毕竟是对言语自身的可控性还不那么看好

一起, 咱们发现Skynet运用的是Actor模型, 也发现大神级的程序员便是有先见.

转载请注明: 战魂小筑http://www.fometaux.com/sunicdavy

感受篇

规划

踏入Golang, 就不要测验规划形式

传统的OO在这儿是不合法的, 测验模仿仅仅一种搞笑

把OO在Golang里换成复合+接口

对完成者来说, 把各种结构都复合起来, 对外露出出一个或多个接口, 接口就好像运用者在完成模型上打出的许多洞

别怕大局函数, 包(Package)能够操控大局函数运用规模.

没必要什么都用interface对外封装, struct也是一种杰出的封装办法

Golang无承继, 因而无需类派生图. 没有派生这种点对点的依靠, 因而不会在许多类联系到来时, 构成冗杂不行改变的树形结构

 

容器

用了很长时刻map, 才发现Golang把map内建为言语特性时, 现已去掉了外置型map的api特性. 一切的拜访和获取都是依照言语特性来做的, 原子化

数组能够了解为底层目标, 你平常用的都是切片, 不是数组, 切片便是指针, 指向数组. 切片是轻量的, 即使值复制也是低损耗的

 

内存

Golang在实践运转中, 你会发现内存可能会疯涨. 但跑上一段时刻后, 就保持安稳. 这和Golang的内存分配, 废物收回有必定的联系

现代的编程言语的内存办理不会很粗犷的直接从OS那儿分配许多内存. 而是按需的不断分配成块的内存.

关于非海量级运用, Golang自身的内存模型彻底能够撑得下来. 无需像12bet相同, 每个工程必做内存池和线程池

Channel

Channel和锁谁轻量? 一句话告知你: Channel自身用锁完成的. 因而在无可奈何时, 仍是尽量削减运用Channel, 但Channel归于言语层支撑, 适度运用, 能够改进代码可读写

转载请注明: 战魂小筑http://www.fometaux.com/sunicdavy

过错

觉得Golang不断的处理err? 那是由于平常在其他言语底子没处理过过错, 要不然便是根部一次性try过一切的反常, 这是一种风险的行为

panic能够被捕获, 因而编写服务器时, 能够做到不挂

 

风险的interface{}

这东西就跟C/12bet里的void*相同的风险, nil被interface{}包裹后不会等于nil持平, 但print出来的确是nil

模板估量能够处理容器内带interface{}的问题. 但新东西引进, 估量又会让现在的哲学一些杂乱

 

转载请注明: 战魂小筑http://www.fometaux.com/sunicdavy

 

初学Tips

言语学习依照官网的教育走, 跑完底子就会了

下载一个LiteIDE, 合作Golang的Runtime,底子开环境就有了

Golang的类库规划办法和C#/12bet都不同, 假如有Python阅历的会感觉毫无违和感

有一万个理由造轮子都请停手, 类库里有你要的东西

写大工程请查找: Golang项目目录结构安排

Golang言语自身自己没有发现bug, 即使有也早就被大神们捉住了. 仅有的一个感觉形似bug的, 常常是结构体成员首字母小写, 可是json又无法序列化出来…

慎用cgo. 官方现已声明未来对cgo不供给完好兼容性. 任何一门言语在前期都需求对C做出支撑, 但后期完善后的不兼容都是常态

 

转载请注明: 战魂小筑http://www.fometaux.com/sunicdavy

 

 



战魂小筑 2015-06-04 17:19 宣布谈论
]]>
12bet++博客-战魂小筑-漫笔分类-Golanghttp://www.fometaux.com/sunicdavy/archive/2015/03/26/210173.html战魂小筑战魂小筑Thu, 26 Mar 2015 09:23:00 GMThttp://www.fometaux.com/sunicdavy/archive/2015/03/26/210173.htmlhttp://www.fometaux.com/sunicdavy/comments/210173.htmlhttp://www.fometaux.com/sunicdavy/archive/2015/03/26/210173.html#Feedback1http://www.fometaux.com/sunicdavy/comments/commentRss/210173.htmlhttp://www.fometaux.com/sunicdavy/services/trackbacks/210173.htmlgolang的time.Format规划的和其他言语都不相同, 其他言语总是运用一些格局化字符进行标明, 而golang呢, 查了网上一些坑比方 自己查了下golang的源码, 发现以下代码
// String returns the time formatted using the format string
//  "2006-01-02 15:04:05.999999999 -0700 MST"
func (t Time) String() string {
    return t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
}

测验将2006-01-02 15:04:05写入到自己的比方中

func nowTime() string {
    return time.Now().Format("2006-01-02 15:04:05")
}

成果回来正确. 询问了下, 听说这个日期是golang诞生的日子… 咋那么自恋呢…

战魂小筑 2015-03-26 17:23 宣布谈论
]]>