作者回复: 这里的锁实际要保护的是 errs.CollectorErrors的读写。 为了提高程序的性能,锁的范围要尽量小
作者回复: 谢谢你的支持.
作者回复: 是我们的软件设计,有一些可以参考的模式。
作者回复: 依赖是通过接口的,不会有这个问题
作者回复: Collect是接口
作者回复: 看以下两端代码: func (agt *Agent) Start() error { if agt.state != Waiting { return WrongStateError } agt.state = Running agt.ctx, agt.cancel = context.WithCancel(context.Background()) go agt.EventProcessGroutine() return agt.startCollectors() } func (agt *Agent) startCollectors() error { var err error var errs CollectorsError var mutex sync.Mutex for name, collector := range agt.collectors { go func(name string, collector Collector, ctx context.Context) { defer func() { mutex.Unlock() }() err = collector.Start(ctx) mutex.Lock() if err != nil { errs.CollectorErrors = append(errs.CollectorErrors, errors.New(name+":"+err.Error())) } }(name, collector, agt.ctx) } if len(errs.CollectorErrors) == 0 { return nil } return errs }
作者回复: 那样是可以的。但是程序就无法管理这个停止过程中Agent产生的错误了
作者回复: 很好的发现。这个是因为Agent.Start()返回时,没有等待Collector的start过程结束。所以,要修正这个问题,只要同步一下就可以。 func (agt *Agent) startCollectors() error { var err error var errs CollectorsError var mutex sync.Mutex var wg sync.WaitGroup for name, collector := range agt.collectors { wg.Add(1) go func(name string, collector Collector, ctx context.Context) { defer func() { mutex.Unlock() }() err = collector.Start(ctx) mutex.Lock() if err != nil { errs.CollectorErrors = append(errs.CollectorErrors, errors.New(name+":"+err.Error())) } wg.Done() }(name, collector, agt.ctx) } wg.Wait() return errs }
作者回复: 因为Collector工作在不同的协程中,所以访问CollectorErrors([] error)添加错误时,需要通过同步量(mutex)来实现线程安全。
作者回复: func (agt *Agent) startCollectors() error { var err error var errs CollectorsError var mutex sync.Mutex for name, collector := range agt.collectors { go func(name string, collector Collector, ctx context.Context) { defer func() { mutex.Unlock() }() err = collector.Start(ctx) mutex.Lock() if err != nil { errs.CollectorErrors = append(errs.CollectorErrors, errors.New(name+":"+err.Error())) } }(name, collector, agt.ctx) } if len(errs.CollectorErrors) == 0 { return nil } return errs } 在相关代码中添加: if len(errs.CollectorErrors) == 0 { return nil }