Golang 游戏leaf系列(九) 官方issues摘录

在查看官方issues时,也发现了一些个人觉得有用的讨论,摘录一下

一、issues 希望可以增强下log的功能

Q:leaf的log蛮好用的了,可以log到文本。但是现在需要做日志分析。要能支持json格式,异步log等等。希望可以加强下。
看了下zap日志库,感觉过去复杂了。有没有简单实用,能分析的日志库?
A:Leaf 的 log 的定位并非用于数据分析,最好额外加一套用于数据分析的机制,同时也保留 Leaf 的 log。

二、issues 服务端崩溃

zcwtop:请问下,你是如何设计“一局游戏开一个Goroutine”的。能否给个简单的demo或者思路。
我自己写,一局游戏基本上是每个操作都放在goroutine里运行的,用的是leaf的顺序goroutine。这样感觉goroutine会非常多,不知道这样设计是不是错了?

exfun:为什么每个操作都要单独开goroutine。我之前就是开太多了,几十局游戏开运行完全跑不出问题。跑几万的次数就崩溃,这就是我开个issue求助的原因,找BUG找半天。我听了作者了。尽量少开,一局游戏的逻辑操作都放一个goroutine里执行,数据同步放到另外一个goroutine专门处理,我们用的Postgress。这样防止并发下未知的RACE。简单点好

zcwtop:是啊。我现在感觉是太多了。我现在的设计是这样的,假如一局游戏的结构是

type T struct {
    *g // leaf 平行的go
    ...
}

func (t *T) add {
    t.Go(func() {
        // ...
    }, func(){
        //...
    })
}

func (t *T) del {
    t.Go(func() {
        // ...
    }, func(){
        //...
    })
}

基本上每个操作都是这样。如果改成一个go运行,我该如何改? 或者你是如何写的,能否给个参考。

exfun:我没有用leaf这个,用go 关键字声明的。leaf的只用了它的消息和工具类这些。我是一局游戏比如game *Game, 然后会在一个goroutinue里面执行,比如 go game.Process() , 然后在process里面完成单局所有的事情。游戏局完了之后,这个goroutine就会执行完,等待GC回收。

zcwtop:那是不是这个Process是一个死循环,用select多路复用等待通道消息,然后执行。我理解是不是类似这样处理:

func (g *Game) Process(...) {
    begin()
    //...

    for {
        select {
        case c:=<-通道1:
            handle1()
        case c := <-通道2:
            handle2()
        }
    }

    //...

    end()
}
func (g *Game)handle1() {
    //...
}
func (g *Game)handle2() {
    //...
}

exfun:写好点应该是这样的,leaf负责消息转发chan通知,来了就处理,注意游戏结束条件。别一直结束不了卡住,这样就会有问题。超时的地方得处理!我们是在线答题的游戏,比较简单。

zcwtop:人多的时候一定要注意别资源竞争(多核下就很容易崩溃),要么用锁,原子,条件变量控制。或者用chan来传递消息。以下是我一个Game一个goroutine来控制游戏过程的流程Process() 。重构后的代码,比之前清晰多了,这也是我第一次写golang,还需要学习的东西很多。

func (GR *GameRoom) Process() {
    // 处理游戏过程结束/正常/异常
    defer func() {
        GR.End()
        if e := recover(); e != nil {
            panic(e)
        }
    }()
    GR.Playing = true
    gameStartTime := conf.GameConfig.StartTime
    robotTime := conf.GameConfig.RobotTime
Playing:
    for {
        select {
        case m := <-GR.MsgChan:
            player := m.P
            switch m.Mtype {
            case MSG_JOIN:
                GR.onJoin(player)
            case MSG_ANSWER:
                GR.onAnswer(player, m.Answer, m.Pm)
            }
        case wf := <-GR.WaitChan:
            switch wf {
            case WAIT_GAME:
                // 游戏开始倒计时,补充一部分AI
                joinRobots(GR, utils.RandIntFrom2(18, 25))
                // 等待是否补充足房间
                time.AfterFunc(time.Second*time.Duration(robotTime), func() {
                    GR.WaitChan <- ON_RO_JOIN
                })
            case ON_RO_JOIN:
                // 不足AI
                joinRobots(GR, 0)
                // 剩余倒计时
                time.AfterFunc(time.Second*time.Duration(gameStartTime-robotTime), func() {
                    GR.WaitChan <- ON_GAME_START
                })
            case ON_GAME_START:
                // 游戏开始
                GR.Start()
            case ON_RO_ANS_1:
                // 机器人第一次回答
                helpRobotAnswer(GR, true, false)
                time.AfterFunc(time.Second*time.Duration(1), func() {
                    GR.WaitChan <- ON_RO_ANS_2
                })
            case ON_RO_ANS_2:
                // 机器人第二次回答
                helpRobotAnswer(GR, false, false)
                time.AfterFunc(time.Second*time.Duration(1), func() {
                    GR.WaitChan <- ON_RO_ANS_3
                })
            case ON_RO_ANS_3:
                helpRobotAnswer(GR, false, true)
                // 倒计时回答结束
                time.AfterFunc(time.Second*time.Duration(GR.AnswerTimeout-4), func() {
                    GR.WaitChan <- ON_ANSWER_END
                })
            case ON_ANSWER_END: // 回答结束,结算
                GR.onAnswerOver()
            case ON_SEND_QUESTION: // 出题
                GR.sendQuestion()
            case MSG_END_GAME: // 游戏结束
                //break game
                break Playing
                // goto END
            }
        }
    }
    //END:
    log.Debug("Game goroutine over ->%s", GR.Uuid)
}
三、Leaf 中如何做消息广播

游戏服务器一定需要用户管理,最常见的方式就是建立用户 ID 到用户实例的映射关系(还有可能存在用户帐号 ID、用户名到用户实例的映射关系)。例如:

users = make(map[int]*User)

User 本身为了简单,可以直接组合 Agent:

type User struct {
    gate.Agent
}

这样的话,广播消息就是:

for _, user := range users {
    user.WriteMsg(msg)
}

一个最简单的广播的例子:打开 Leafserver game/internel/chanrpc.go 文件,加入一个全局变量。

var agents = make(map[gate.Agent]struct{})
agents 的管理:

// agent 被创建时
func rpcNewAgent(args []interface{}) {
    a := args[0].(gate.Agent)
    agents[a] = struct{}{}
}

// agent 被关闭时
func rpcCloseAgent(args []interface{}) {
    a := args[0].(gate.Agent)
    delete(agents, a)
}
由此可见 agents 中保存了当前所有连接,广播的处理:

for a := range agents {
    a.WriteMsg(msg)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容