前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >由Go语言并发模型想到游戏服务器并发

由Go语言并发模型想到游戏服务器并发

作者头像
李海彬
发布2018-03-26 16:06:18
1.3K0
发布2018-03-26 16:06:18
举报
文章被收录于专栏:Golang语言社区Golang语言社区

这段时间看了一些Go语言相关的东西,发现Go语言的最大特性并发模型类似于C++里面的线程池,正好我们项目服务器也是用的线程池,记录下。

  Go语言的并发单位是语言内置的协程,使用关键字go+函数创建一个新的协程,新创建的协程会自动加入到协程调度上下文的等待调度队列,一个协程调度上下文对应一个线程,一个协程调度上下文对应多个协程。新加入的协程会动态负载到各个调度上下文,如果所有调度上下文的平均负载较高时,总调度器会自动创建新的线程和对应的调度上下文用于工作。整体上看,是N个线程:N个调度上下文:M个协程的关系。

  我们项目服务器线程架构使用boost::threadpool作为底层,按照配置设定的线程数量启动threadpool,驱动所有Invoker单元,各个Invoker再驱动持有自己的Service运转。单个Service可以持有一个或多个Invoker。在threadpool和Service之间加入Invoker层,逻辑更清晰,实现了Service(父)和ServiceExec(子)的概念。

  本质上,Go语言的协程和我们的线程池+Service结构都实现的是线程与逻辑体的N对M映照关系,并且逻辑层完全屏蔽掉线程的概念。差别在于,Go语言的执行体是基于协程,协程切换是用户态切换,而我们的Service间切换是操作系统线程的切换,会有大很多的代价。Go语言是内置支持并发,所以在智能负载这样的细节上也比C++线程池会更强大。经验丰富的C++程序员才能合理驾驭的线程池在Go语言里面就是一个关键字的使用,语言带来的生产力提升真是巨大。

  再看线程间通信,Go语言使用内置的通道(chan)类型,我们项目写了一套Service间Message通信,本质上都是基于消息的通信模型。

  我们使用的是消息队列轮询机制,每个Service持有一个std::list,Service之间发消息通过ServiceManager中转,Service在心跳中取出list里面的消息并处理,因为是线程间共享变量,所以读取添加消息都加锁。

  对于Go语言中带缓存通道,在通道的缓存队列满之前,往通道里面塞数据是非阻塞操作;通道缓存非空的情况下,从通道取数据也是非阻塞操作,这两种情况与我们的Message类似,区别在于Go语言的通道在缓存满时塞数据和缓存空时取数据是阻塞操作,也就是说Go语言的通道带有同步语义,而我们的Message是没有这个功能的。当然,我觉得作为游戏服务器是不怎么需要线程间同步的,基于轮询的Message处理机制已经完全够用。Go语言通道强大在于,每个通道都维护了塞数据协程队列和取数据协程队列,这极大了扩展了通道的能力,真正达到了通道将不同协程连通的目的。

  看了Go语言之后,真心觉得用来开发网游服务器实在是太合适了,协程在并发有优势,开发效率会比C++提升不少,而执行效率据说是不会有太大下降,并且语言语法都很和我的胃口。

本文来自:博客园

感谢作者:gns3

查看原文:由Go语言并发模型想到游戏服务器并发

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档