package err_group import ( "context" "golang.org/x/sync/errgroup" "math/rand" "time" ) type WeatherData struct { City string Weather string Temp int } var WeatherList = []string{"晴", "阴", "多云", "小雨", "大雨"} // fetchWeatherData 获取天气数据 func fetchWeatherData(ctx context.Context, city string) (*WeatherData, error) { done := make(chan struct{}, 1) // 用于指示数据获取成功完成 data := new(WeatherData) // 启动一个goroutine来获取天气数据 go func() { // 这里仅为示例,实际中这里会是API调用 // 为了模拟可能出现的超时或错误情况,这里随机地休眠一段时间 time.Sleep(time.Duration(rand.Intn(500)) * time.Millisecond) data.City = city // 随机天气 data.Weather = WeatherList[rand.Intn(len(WeatherList))] // 随机温度 data.Temp = rand.Intn(40) done <- struct{}{} }() select { case <-ctx.Done(): // 如果上下文被取消,返回错误 return nil, ctx.Err() case <-done: // 如果数据获取成功完成,返回数据 return data, nil } } func GetAllCityWeatherData(timeOut time.Duration) ([]*WeatherData, error) { // 创建一个携带cancel的context ctx, cancel := context.WithTimeout(context.Background(), timeOut) defer cancel() // 确保所有路径都调用cancel // 初始化一个ErrGroup对象 g, ctx := errgroup.WithContext(ctx) // 城市列表 cities := []string{"New York", "Tokyo", "Berlin", "Paris", "Beijing"} list := make([]*WeatherData, 0, len(cities)) // 循环启动goroutine来获取每个城市的天气数据 for _, city := range cities { city := city g.Go(func() error { // FetchWeatherData使用了上下文,如果上下文被取消,它应该立刻尝试返回 data, err := fetchWeatherData(ctx, city) if err != nil { return err } // 如果没有错误,将数据添加到列表中 list = append(list, data) return nil }) } // 等待所有goroutine完成或出现错误 if err := g.Wait(); err != nil { return nil, err } return list, nil }