记一次Golang routine卡死

hgd7123 · · 3772 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Go语言最方便的地方在于可以自由自在的起routine,并且不用自己维护队列。

 

一个很简单的处理模型,针对于长连接活动平凡的链接独立routine进行处理,方便同一连接上下文关联,read routine A讲接收到的消息解包生成消息丢到对应socket的routine B channel中进行处理,routine B在根据不同的任务丢到对应的routine B1或者 routine B2中进行处理,

我们需要一个channel回写routine B1 routine B2的退出信号给你 B 以便B进行响应处理。

那么这么想的话 B 和B1 B2 需要两个channel进行消息通信

伪代码如下,未做友好处理。

var B1 B1Consumer
var B2 B2Consumer

//statch 回写子routine的状态
statch := make(chan StatMsg,1)
B1Ch := make(chan Msg,100)
B2Ch := make(chan Msg,100)
go B1(B1ch,statch)
go B2(B2ch,statch)

for{
    select{
    case cmsg, ok := <-BCh:
        if cmsg.type == B1{
            B1ch<-cmsg
        }else{
            B2ch<-cmsg
        }
    case StatMsg := <-statch:
        deal_state(msg)
    }
}

乍一看没什么问题,后面再测试过程中 偶尔发现调用接口没有响应超时。

仔细排查后发现,B1 routine 在退出时回写了一个Done的StatMsg,然后就退出了。

此事Bch还在写数据如果此时B1ch写满了,那么写channel就会卡死,而B1退出的信号已经发送了 不在处理新数据了,那么B routine就会一直卡死在

B1ch<-cmsg

此时已经B routine 已经无法进行下一次select的操作,进而等Bch channel写满 卡死读取routine,等多个读取routine卡死,客户端表现就是无响应了 超时了。

 

找到问题解决办法就简单了。

增加写入channel超时 并且增加statch 的大小

statch := make(chan StatMsg,MAXCHANNELSIZE) 

select {
            case B1ch <- cmsg:
            case <-time.After(time.Duration(CLOSETIMEOUT) * time.Second):

}

 

加大channel大小 避免多次触发超时,如果一旦出现超时,将超时的任务释放掉。


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:hgd7123

查看原文:记一次Golang routine卡死

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3772 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传