go-study/err_group/weather.go
fantasticbin 5b48ea1a62 使用codex优化代码,具体如下:
主要优化

  - err_group:去掉多余 goroutine,避免潜在泄漏;并把并发 append 改为按下标写
    入,消除数据竞争。
  - err_group 测试稳定性增强:放宽超时并增加结果长度断言。
  - semaphore:修复等待队列元素类型断言错误(*waiter);补充非法参数校验(负数
    acquire/release)。
  - SemaChan:修复 Lock/Unlock 逻辑(初始化令牌桶),避免永久阻塞。
  - observer:修复“每次 Notify 都启动新 fanout 协程”的问题:改为 sync.Once 只启动一次
    fanOut。
  - observer:修复并发读写观察者列表问题:给 Attach/Detach/fanOut 增加读写锁保护。
  - observer:去掉 fanout 内部额外再起 goroutine和自动关闭所有 observer 的行为,避
    免重复关闭/竞态风险(仍保留 Detach 时关闭单个 observer)。
  - lock_free:修复可取消延迟队列的计数错误与 timers map 并发访问问题。
  - lock_free:checkAckStatus 改为非阻塞读取,避免入队路径被卡住。
  - routine:提供默认空任务并忽略 nil taskFn,防止空指针调用。
  - ticker:发送改为非阻塞,Stop 幂等化,降低阻塞和重复关闭风险。
  - query_builder:WaitAndGo 增加 goroutine 内 panic 转 error;测试里
    的 GORM filter 链式写法修正。

  新增测试

  - 新增 semaphore 测试,覆盖 Acquire/Release/TryAcquire 与 SemaChan 并发上限。
2026-03-05 21:53:11 +08:00

73 lines
1.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package err_group
import (
"context"
"math/rand"
"time"
"golang.org/x/sync/errgroup"
)
type WeatherData struct {
City string
Weather string
Temp int
}
var WeatherList = []string{"晴", "阴", "多云", "小雨", "大雨"}
// fetchWeatherData 获取天气数据
func fetchWeatherData(ctx context.Context, city string) (*WeatherData, error) {
// 这里仅为示例,实际中这里会是 API 调用
// 为了模拟可能出现的超时或错误情况,这里随机休眠一段时间
delay := time.Duration(rand.Intn(500)) * time.Millisecond
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(delay):
}
return &WeatherData{
City: city,
// 随机天气
Weather: WeatherList[rand.Intn(len(WeatherList))],
// 随机温度
Temp: rand.Intn(40),
}, 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, len(cities))
// 循环启动goroutine来获取每个城市的天气数据
for i, city := range cities {
g.Go(func() error {
// FetchWeatherData使用了上下文如果上下文被取消它应该立刻尝试返回
data, err := fetchWeatherData(ctx, city)
if err != nil {
return err
}
// 每个协程写入固定下标,避免并发 append 数据竞争
list[i] = data
return nil
})
}
// 等待所有goroutine完成或出现错误
if err := g.Wait(); err != nil {
return nil, err
}
return list, nil
}