From e57918df0528eca1d3074bd189f246493ea7102e Mon Sep 17 00:00:00 2001 From: wangwenbin Date: Thu, 28 Dec 2023 17:41:52 +0800 Subject: [PATCH] =?UTF-8?q?ErrGroup=E4=BD=BF=E7=94=A8=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- err_group/weather.go | 80 +++++++++++++++++++++++++++++++++++++++ err_group/weather_test.go | 17 +++++++++ 2 files changed, 97 insertions(+) create mode 100644 err_group/weather.go create mode 100644 err_group/weather_test.go diff --git a/err_group/weather.go b/err_group/weather.go new file mode 100644 index 0000000..1ebe5d2 --- /dev/null +++ b/err_group/weather.go @@ -0,0 +1,80 @@ +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 + list := make([]*WeatherData, 0) + + // 初始化一个ErrGroup对象 + g, ctx := errgroup.WithContext(ctx) + + // 城市列表 + cities := []string{"New York", "Tokyo", "Berlin", "Paris", "Beijing"} + + // 循环启动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 +} diff --git a/err_group/weather_test.go b/err_group/weather_test.go new file mode 100644 index 0000000..e1245c2 --- /dev/null +++ b/err_group/weather_test.go @@ -0,0 +1,17 @@ +package err_group + +import ( + "testing" + "time" +) + +func TestGetAllCityWeatherData(t *testing.T) { + list, err := GetAllCityWeatherData(500 * time.Millisecond) + if err != nil { + t.Fatal(err) + } + + for _, data := range list { + t.Logf("%s: %s, %d", data.City, data.Weather, data.Temp) + } +}