问题描述:
1、我在主进程中,通过go启动了两个协程来处理labor的运行。主进程定位为g0,两个协程分别定义为g1和g2
2、同时在主进程中,通过运行 runConfigChangedMonitor 来定时监控配置文件是否发生变化,如果发生变化就退出
3、退出方法为Shutdown(),在该方法内部,调用labor的Shutdown()来关闭labor的运行,之后通过向chan bool channel设置一个
bool值来尝试退出
4、但是在Shutdown()方法中,
g1和g2的Shutdown()能顺利的执行
但是g0的如下这条语句的执行被hang住了
o.mQuit <- true
原因是:
1、默认初始化时使用的chan bool是无缓存channel
2、当在主协程g0内部向一个无缓存channel设置值的时候,默认会被hang住,除非本协程内部能从channel消费数据。但是由于设置和和消费都是同一个协程,所以无缓存情况下,会出现hang的情况
3、在g0设置g1和g2的时候,都没有问题(即便g1和g2协程内部也是定义的无缓存bool channel,但是设置和消费是两个不同的协程)
解决方案:
1、要么设置的时候,采用go的匿名方法,通过go 执行匿名方法来实现
2、要么将bool channel 初始化为带缓存的channel也可以解决
主要代码如下:
type LaborManager struct {
mLaborConfs map[string]*LaborConf
mConfigMD5 string
mLabors map[string]ILabor
mTjApi IDataaccess
mFileReader info_reader.IFileReader
mQuit chan bool
mTicker *time.Ticker
mLogger tj.Logger
}
func NewLaborManager(tjApi IDataaccess, fileReader info_reader.IFileReader) *LaborManager {
fileMonitorDuration, _ := time.ParseDuration("10s")
return &LaborManager{
mLaborConfs: map[string]*LaborConf{},
mFileReader: fileReader,
mTjApi: tjApi,
mLabors: map[string]ILabor{},
// 如果初始化成一个不带缓存的bool chan,会出现Shutdown方法的向channel设置true的操作会出现hang的情况
//mQuit: make(chan bool),
// 这里初始化一个带1个数据的缓存的bool channel来避免在相同的进程内部操作chan出现hang
mQuit: make(chan bool, 1),
mTicker: time.NewTicker(fileMonitorDuration),
mLogger: tj.GetLogger("labor_manager"),
}
}
func (o *LaborManager) Shutdown() {
for _, labor := range o.mLabors {
labor.Shutdown()
o.mLogger.Infof("labor done")
}
/*
当bool channel初始化的时候就是带缓存的,直接向chan中设置并不会hang
*/
o.mQuit <- true
o.mLogger.Infof("quit is setted to true")
/*
如果bool channel为无缓存channel,使用这段代码可是避免hang住
go func() {
o.mQuit <- true
o.mLogger.Infof("quit is setted to true")
}()
*/
}
func (o *LaborManager) runConfigChangedMonitor() {
for {
select {
case <-o.mQuit:
o.mLogger.Infof("config monitor has been exited")
o.mLogger.Flush()
o.mTicker.Stop()
return
case <-o.mTicker.C:
o.mLogger.Infof("config monitor begin...")
if o.IsConfigChanged() {
o.mLogger.Infof("config changed, exiting...")
o.Shutdown()
}
}
}
}
程序输出结果:
INFO labor_manager 2018/11/14 16:04:13.796465 labor_manager.go:171: config monitor begin...
INFO labor_manager 2018/11/14 16:04:23.796459 labor_manager.go:171: config monitor begin...
INFO labor_manager 2018/11/14 16:04:33.796429 labor_manager.go:171: config monitor begin...
INFO labor_manager 2018/11/14 16:04:43.796482 labor_manager.go:171: config monitor begin...
INFO labor_manager 2018/11/14 16:04:43.796621 labor_manager.go:173: config changed, exiting...
INFO labor_manager 2018/11/14 16:04:43.796638 labor_manager.go:99: labor done
INFO labor_manager 2018/11/14 16:04:43.796656 labor_manager.go:99: labor done
INFO labor_manager 2018/11/14 16:04:43.796660 labor_manager.go:103: quit is setted to true
INFO labor_manager 2018/11/14 16:04:43.796666 labor_manager.go:166: config monitor has been exited