当前位置: 首页 > news >正文

[Go WebSocket] 多房间的聊天室(五)用多个小锁代替大锁,提高效率

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

背景

在专栏《Go WebSocket》里,有一些前置文章:

第一篇文章:《为什么我选用Go重构Python版本的WebSocket服务?》,介绍了我的目标。

第二篇文章:《你的第一个Go WebSocket服务: echo server》,介绍了一下怎么写一个WebSocket server。

第三篇文章:《单房间的聊天室》,介绍了如何实现一个单房间的聊天室。

第四篇文章:《多房间的聊天室(一)思考篇》,介绍了实现一个多房间的聊天室的思路。

第五篇文章:《多房间的聊天室(二)代码实现》,介绍了实现一个多房间的聊天室的代码。

第六篇文章:《多房间的聊天室(三)自动清理无人房间》,介绍了如何清理无人的房间,避免内存无限增长的问题。

第七篇文章:《多房间的聊天室(三)自动清理无人房间》,介绍了如何避免并发导致的资源竞争的问题,是通过悲观锁解决的。

第八篇文章:《多房间的聊天室(三)自动清理无人房间》,介绍了基于Go WebSocket手写一个简单的Web Shell,可以体验直接在浏览器中输入linux命令的感觉~

温馨提示:阅读本文前,需要至少阅读前7篇文章。如果你没阅读前7篇文章,一定要先看一下,因为这篇文章更复杂,如果你不弄懂上面几篇,这篇可能跟不上节奏噢。

回顾:register和unregister竞争

上篇文章我们提到,存在黑天鹅事件(小概率事件),register和unregister会竞争资源,导致数据异常。

最终我们通过增加「悲观锁」解决问题。

需要注意的是,我们上文加的锁是一个全局的锁。

这意味着,同时有100个客户端(即使是不同的房间)请求连接时,他们必须排好队,一个一个处理。等上一个请求加锁、释放锁后,才处理下一个请求。不能发挥goroutine并行的优势。

换句话说,这个「锁」太大了!影响了程序运行效率。

怎么解决呢?我们把「锁」拆分成更多小锁,每个房间用一把锁,这就解决了问题。保证可以同时处理「不同的房间的用户连接请求」。

用小锁代替大锁

用「多个小锁」代替「大锁」,可以显著提高各场景下的并行效率。

如下:

main.go

1.png

2.png

client.go

3.png

hub.go

4.png

但是给每个房间加锁,存放在同一个map里,读取这个map有需要引入一个全局锁mutexForRoomMutexes

其实,大可不必担心,现在已经优化了很多了!

因为你可以看到,这个锁释放的非常快,影响不大。但是上篇文章的锁mutex,不仅是全局锁,而且占用时间较长。

源码

仓库地址:github.com/HullQin/go-websocket-examples

关注这个commit:github.com/HullQin/go-websocket-examples/commit/b12271a9531360d407c22c54c854e177e7e48fda

写在最后

我是HullQin,公众号线下聚会游戏的作者(欢迎关注公众号,发送加微信,交个朋友),转发本文前需获得作者HullQin授权。我独立开发了《联机桌游合集》,是个网页,可以很方便的跟朋友联机玩斗地主、五子棋等游戏,不收费没广告。还开发了《Dice Crush》参加Game Jam 2022。喜欢可以关注我 HullQin 噢~我有空了会分享做游戏的相关技术。

相关文章:

  • 我在windows环境下的YOLOV3环境搭建过程
  • bat goto 还是 call
  • JVM垃圾回收系列之垃圾收集算法
  • 计算机毕业设计选题推荐 40个高质量计算机毕设项目分享【源码+论文】(三)
  • BDD - SpecFlow BDD 测试实践 SpecFlow + MSTest
  • CRM项目记录(四)
  • React组件的生命周期函数
  • FFmpeg源码分析:avformat_open_input()打开媒体流
  • 深入理解关键字 一(auto,register,static,sizeof)
  • 基于Springboot+vue的停车场管理系统(Java毕业设计)
  • 详解CAN总线:CAN总线报文格式—数据帧
  • mysql进阶:canal实现mysql数据同步到redis|实现自定义canal客户端
  • React路由三种渲染方式、withRouter高阶组件、自定义导航组件
  • FaceNet-pytorch(fixing data imbalance-CASIA)
  • 【内核的设计与实现笔记】| 【01】初步了解内核
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • C++类中的特殊成员函数
  • crontab执行失败的多种原因
  • Hibernate最全面试题
  • IndexedDB
  • JavaScript 基本功--面试宝典
  • JavaScript中的对象个人分享
  • k个最大的数及变种小结
  • Laravel 实践之路: 数据库迁移与数据填充
  • Laravel 中的一个后期静态绑定
  • Making An Indicator With Pure CSS
  • MySQL数据库运维之数据恢复
  • Octave 入门
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • -- 查询加强-- 使用如何where子句进行筛选,% _ like的使用
  • 大整数乘法-表格法
  • 开发基于以太坊智能合约的DApp
  • 开源地图数据可视化库——mapnik
  • 坑!为什么View.startAnimation不起作用?
  • 蓝海存储开关机注意事项总结
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 使用docker-compose进行多节点部署
  • 使用putty远程连接linux
  • 正则表达式小结
  • 智能网联汽车信息安全
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​人工智能书单(数学基础篇)
  • (二)学习JVM —— 垃圾回收机制
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (介绍与使用)物联网NodeMCUESP8266(ESP-12F)连接新版onenet mqtt协议实现上传数据(温湿度)和下发指令(控制LED灯)
  • (强烈推荐)移动端音视频从零到上手(下)
  • (四)鸿鹄云架构一服务注册中心
  • (四)图像的%2线性拉伸
  • (一)基于IDEA的JAVA基础10
  • (转)PlayerPrefs在Windows下存到哪里去了?