多协程同步模型

图1

在Go程序启动时,指定了多核多线程运行模式下,每个协程都可能被投递到不同的线程上被执行。

类似多线程编程,需要考虑访问互斥资源的问题。

常见的,会使用互斥锁等机制,来处理这类问题。Go语言也是支持的。

同时,Go语言提供了chan机制,也就是上图中所画的模型。

这种同步模型的好处有:

  • 相关的逻辑都在1根主协程中执行,从而把相关逻辑变成了同步编程。
  • 其他协程通过chan,类似投递消息的方式,与主协程互动。即不直接操纵互斥资源,从而避免了访问互斥问题。

此外,与一些常见的游戏框架比,一些游戏框架会把所有业务逻辑串行执行。

而这种模型,则是把1个房间内的游戏逻辑串行化。从而使所有房间的游戏逻辑并行执行。这样可以更好的利用CPU了

项目代码示例分析 - chan_PlayerCmd

上一节中的 加入房间、销毁房间,都是用过chan的方式告知房间主循环,并在房间主循环内实现了玩家加入房间、房间销毁操作。

这里再举个例子,巩固下。

我们来看下RoomServer,从收到玩家消息,经过 chan(chan_PlayerCmd),到房间主循环执行的过程

  • 收到玩家消息

    func (this *PlayerTask) ParseMsg(data []byte, flag byte) bool {
    // ... (无关代码略)
    switch cmd {
    default:
        this.room.PostPlayerCmd(this.id, cmd, data, flag)
    }
    return true
    }
    
  • PostPlayerCmd函数

    func (this *Room) PostPlayerCmd(playerID uint64, cmd usercmd.MsgTypeCmd,
    data []byte, flag byte) {
    
    playerCmd := &PlayerCmd{playerID: playerID, cmd: cmd, flag: flag}
    // Must copy data.
    playerCmd.data = make([]byte, len(data))
    copy(playerCmd.data, data)
    this.chan_PlayerCmd <- playerCmd
    }
    

    最后一行,把消息投递给了chan_PlayerCmd

  • 房间主循环执行chan_PlayerCmd投递来的消息

    func (this *Room) Loop() {
    // ... (无关代码略)
      for {
          select {
          // ... (无关代码略)
          case op := <-this.chan_PlayerCmd:
              if !this.IsClosed() {
                  player, ok := this.Players[op.playerID]
                  if ok {
                      player.OnRecvPlayerCmd(op.playerID, op.cmd, op.data, op.flag)
                  } else {
                      glog.Info("chan_PlayerCmd:no player,", op.playerID, " cmd:", op.cmd)
                  }
              }
          // ... (无关代码略)
          }
      }
    }
    

    player.OnRecvPlayerCmd 函数内根据消息内容,实现分别处理

以上

results matching ""

    No results matching ""