等待一个协程组全部正确完成则结束;但其中一个协程发生错误,这时候就会阻塞,全部停止运行(本次任务失败)以免浪费系统资源,此时可以结合通道(channel)或者 select 语句两种方式来处理。
1、考虑使用两个通道:一个用于报告错误,另一个用于通知所有协程停止。在协程内部捕获错误,并将错误信息发送到错误通道。另一个协程监听错误通道,一旦有错误发生,就会向停止通知通道发送信号,通知所有协程停止运行。
package main import ( "fmt" "sync" ) func worker(id int, errCh chan error, wg *sync.WaitGroup) { defer wg.Done() // 模拟错误 if id == 2 { errCh <- fmt.Errorf("error occurred in worker %d", id) return } // 做一些工作 fmt.Printf("Worker %d is working...\n", id) } func main() { var wg sync.WaitGroup errCh := make(chan error) stopCh := make(chan struct{}) for i := 0; i < 5; i++ { wg.Add(1) go worker(i, errCh, &wg) } go func() { err := <-errCh if err != nil { fmt.Println("Error occurred:", err) close(stopCh) } }() go func() { wg.Wait() close(errCh) }() // 等待通知,停止所有协程 <-stopCh fmt.Println("All workers stopped.") }
errCh
通道用于发送错误信息,stopCh
通道用于通知所有协程停止。如果有一个协程发生错误,就会关闭 stopCh
通道,通知其他协程停止运行。
2、select
语句是 Go 中用于多路非阻塞的关键字,可以用于监听多个通道的操作。你可以在 select
语句中组合使用 WaitGroup
和通道来实现对协程组的控制。
package main import ( "fmt" "sync" ) func worker(id int, errCh chan error, wg *sync.WaitGroup) { defer wg.Done() // 模拟错误 if id == 2 { errCh <- fmt.Errorf("error occurred in worker %d", id) return } // 做一些工作 fmt.Printf("Worker %d is working...\n", id) } func main() { var wg sync.WaitGroup errCh := make(chan error) for i := 0; i < 5; i++ { wg.Add(1) go worker(i, errCh, &wg) } go func() { wg.Wait() close(errCh) }() for { select { case err, ok := <-errCh: if ok { fmt.Println("Error occurred:", err) // 处理错误,根据需要执行相关操作 } else { fmt.Println("All workers completed successfully.") return } } } }
select
语句监听 errCh
通道,等待错误消息。当收到错误消息时,可以根据需要执行相应的错误处理。当 errCh
通道关闭时,ok
的值为 false
,表示所有协程已经成功完成。
标签:wg,waitgroup,协程,错误,errCh,sync,如何,通道 From: https://www.cnblogs.com/beatle-go/p/17881910.html