【犯傻经历】虽然用原子加减来限制协程总数,但是协程加上了永不退出的代码
代码大致如下
var coroutineCount int64 = 0
const maxCoroutineCount = 4000
const defaultSleepMs = 100
func Inc(){
atomic.AddInt64(&coroutineCount, 1)
}
func Dec(){
atomic.AddInt64(&coroutineCount, -1)
}
func job1(){
Inc()
defer Dec()
//do something
}
func job2(){
Inc()
defer Dec()
//do something
for {
coroutineCount := atomic.LoadInt64(&coroutineCount)
if coroutineCount>=maxCoroutineCount{
time.Sleep(defaultSleepMs*time.Millisecond)
continue
}
break
}
//do something
}
func genJob(){
for {
for {
coroutineCount := atomic.LoadInt64(&coroutineCount)
if coroutineCount>=maxCoroutineCount{
time.Sleep(defaultSleepMs*time.Millisecond)
continue
}
break
}
go job1()
go job2()
}
}
这样的代码一开始很好,跑几分钟后莫名的停止了。
导致问题的代码是 job2()中的那个循环检查:
for {
coroutineCount := atomic.LoadInt64(&coroutineCount)
if coroutineCount>=maxCoroutineCount{
time.Sleep(defaultSleepMs*time.Millisecond)
continue
}
break
}
原因是:某一瞬间如果协程的数量大于等于maxCoroutineCount的时候,这个循环几乎不会结束。
教训:
- 产生任务的生产者,对协程数量做检查,并进行等待,是对的;但是执行具体任务的协程一定要在确定的时间内结束,任何可能陷入永远循环的地方都要避免;
- 如果一定要等待,设定一个超时时间,不能无限等待;
- 最好加上监控计数,当某个位置卡死的时候,能够快速定位到。