前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >终于遇到goroutine死锁的BUG了

终于遇到goroutine死锁的BUG了

作者头像
李海彬
发布2018-03-23 11:20:41
1.1K0
发布2018-03-23 11:20:41
举报
文章被收录于专栏:Golang语言社区Golang语言社区

今天测试用Go语言写的角色服务器,发现在模拟大量客户端获取角色列表的时候会卡住,但是服务器程序的CPU占用率为零。分析并经过代码检查确认是goroutine死锁。

此问题涉及到的代码主要是一个database类,封装了角色数据的一些数据库操作。虽然sql.DB后台支持连接缓冲池,但是为了限制资源的使用,我仍然在database类里做了并发数的限制,角色数据的每个操作必须先获得令牌才能进行后续操作,操作完成后归还令牌。代码主要结构如下所示:

import "database/sql"

const DBCONN_MAXCOUNT = 128

type database struct {

db *sql.DB

tokens chan int

}

func (p *database) Open(source string) error {

db, err := sql.Open("mysql", source) if err != nil {

return err

} p.db = db p.tokens = make(chan int, DBCONN_MAXCOUNT) for i := 0; i < DBCONN_MAXCOUNT; i++ {

p.tokens <- 1

} return nil

}

func (p *database) Close() {

p.db.Close()

}

func (p *database) GetRoleData(name string) ([]byte, error) {

token := <-p.tokens defer func() {p.tokens<-token}() //相关数据库操作...

}

func (p *database) DeleteRole(name string) error {

token := <-p.tokens defer func() {p.tokens<-token}() //相关数据库操作...

}

BUG的原因是在DeleteRole函数里其实进行了一些数据库操作,包括为了检查角色数据是否需要放到回收库需要先获取角色数据检查角色的等级等。其中获取角色数据就调用到了GetRoleData函数。这就导致一种可能性:如果所有客户端都执行到DeleteRole函数里,准备执行GetRoleData函数时没有可用令牌,就会集体陷入死锁。

解决办法是定义了一个不需要更底层的函数getRoleData,供GetRoleData和DeleteRole函数调用,从而不需要申请多个令牌。

func (p *database) getRoleData(name string) ([]byte, error) {

//相关数据库操作...

}

func (p *database GetRoleData(name string) ([]byte, error) {

token := <-p.tokens defer func() {p.tokens<-token}() return p.getRoleData(name)

}

func (p *database) DeleteRole(name string) error {

token := <-p.tokens defer func() {p.tokens<-token}() data, err := p.getRoleData(name) if err != nil {

return err

} //其他操作...

}

总结:

1.最好不要设计成做一件事情需要获取N个资源,然后依次去申请。如果不能避免申请多个资源,也应该按照固定次序去申请,否则会导致死锁(本例中是不小心导致的,因为申请令牌是后加的)。这是所有编程语言设计并发程序的通用规则。

2.函数分级。一个类(结构)的暴露给类(结构)外部使用的函数最好不要相互调用。如果有共用代码,可以提取为更底层的一个内部函数,供给多个上一级的函数使用。这个不处理好容易导致以后调整功能需要修改代码时出问题。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档