使用 go 携程出现bug的反思

使用 go 携程出现bug的反思

为何想到用 go 携程

总所周知,go 语言的 go routine,简单高效地为我们提供了并发的能力,我们只需要用关键字 go 就可以轻松地使用 go 的携程,例如下面所示,这样代码之间就可以异步执行了,可以提高代码的运行速度

go 复制代码
func main(){
   fmt.Println("使用 go 携程")
   go func(){
      fmt.Println("这里使用了 go 携程")
   }
   fmt.Println("主携程运行完毕")
}

但如果使用不当,也会产生一些 bug,导致服务出错甚至崩溃

使用的携程过多,但是机器的cpu出现尖刺,任务没有继续执行

当时有个需求,是根据游戏的对局记录去分析用户的行为属性,进行标记,第一期的想法是一天跑一次对局记录,每天大概有几百万的数据,为了效率的着想,使用了 golang 的携程,并且犯了懒症,使用了 funk 这个库的 Uniq 方法去获取记录中不同的游戏id,没想到 funk 这个里面使用了反射,导致效率贼慢,另外一个就是一天的记录里,游戏的 id 实在太多了,产生的携程就更多了(菜鸡🤣),再加上前一两天居然跑得一切正常,导致刚开始并没有发现这个问题,后面的解决方式很简单,去掉 funk 这个库,直接使用 for 循环,然后去掉 go 携程,直接用遍历,用 map 来保存所有的 gid

(注释代表删掉的代码),

show the code (已做脱敏处理)

后面产品要求实时生效,直接抛弃了这份代码,将信息直接存入mq,然后去消费mq,写着写着发现这有点类似于责任链的模式,于是又引入了责任链的模式,自此,代码看起来就清晰明了,修改和添加规则也变得很容易了,每一个 _builder.go 文件代表一个规则,规则里面一环套一环,一层层执行计算出值, ixxxbuilder.go 负责调用每一个规则的执行

并发读写 map 产生的 fatal error

有个服务,新增了某个功能后,偶发这个并发的问题,导致服务重启,查看日志是由于并发读写 map 导致的,后续的解决办法其实就是将这段执行和主线程顺序执行了(这里有个业务相关的点是用户的某个信息,这个服务是保存在内存中,然后在执行的某个阶段再进行更新倒库,由于之前的服务不是我写的,我更新的代码中,是给这个字段加上相应的值,是直接拿库的数据替换掉这个值了),针对这个问题,解决的方案其实将这个需要加的数值,放到一个临时变量,再给这个字段加上去,而不是更新后之后,再拿数据库里的值

并发导致的 data race

时机非常巧,刚好这几天大学的同学问了我一个问题

问: 一个bool变量,一个线程写,多个线程读,需要加锁吗

答: 要,读的过程有可能写,会不一致,读写锁就好了,不用互斥锁

问: 他就一个bool值,感觉你加不加锁都一样

答: 一样的吧 还是会有数据不一致的问题 你可以用go race看看会不会产生data race情况

问: 好像加锁也没啥意义

答: 写个最小demo 看下你这种情况 会不会产生 data race 情况,如何会的话 就算你不要求强一致性 也会导致服务崩溃重启(这里说错了,不会的)

于是我吭呲吭呲就开始写最小 demo

用 go race 检测,发现确实会发生 data race 的情况

于是我建议他使用 atomic,并且也写了个最小 demo

完美,用 atomic 后发现确实不会出现这种 data race 的情况了

但是这时候我同学还是不想用,于是我用网上看到的一句话回复他,

"Any race is a bug. When there is a race, the compiler is free to do whatever it wants"

总结

从上面几种情况看,其实最终的解决办法大多是将其顺序执行了,所以用携程时还是得想一想,是否适合当前的场景。

相关推荐
SomeBottle19 小时前
【小记】解决校园网中不同单播互通子网间 LocalSend 的发现问题
计算机网络·go·网络编程·学习笔记·计算机基础
且去填词1 天前
深入理解 GMP 模型:Go 高并发的基石
开发语言·后端·学习·算法·面试·golang·go
大厂技术总监下海1 天前
向量数据库“卷”向何方?从Milvus看“全功能、企业级”的未来
数据库·分布式·go·milvus·增强现实
冷冷的菜哥1 天前
go(golang)调用ffmpeg对视频进行截图、截取、增加水印
后端·golang·ffmpeg·go·音视频·水印截取截图
Grassto2 天前
深入 `modload`:Go 是如何加载并解析 module 的
golang·go·go module
帅猛的Shic2 天前
Kubernetes Service深度解析:为什么Pod需要稳定接入点
kubernetes·go
molaifeng2 天前
Token:AI 时代的数字货币——从原理到计费全解
人工智能·ai·大模型·llm·go·token
天天进步20153 天前
KrillinAI 源码级深度拆解四: 告别违和感:深度剖析 KrillinAI 中的 Lip-sync 唇形对齐技术实现
go
用户1296157358554 天前
Go语言云原生与微服务架构终极实践指南
go
踏浪无痕4 天前
Go 的协程是线程吗?别被"轻量级线程"骗了
后端·面试·go