Go语言实现时间滑动窗口算法 动态计算增加量、最大值、最小值
// 时间窗口 var fiveMinAccMap = NewAccumulatorsMap(5 * time.Minute) var tenMinAccMap = NewAccumulatorsMap(10 * time.Minute) var fifteenMinAccMap = NewAccumulatorsMap(15 * time.Minute) var thirtyMinAccMap = NewAccumulatorsMap(30 * time.Minute) var oneHourAccMap = NewAccumulatorsMap(time.Hour) // Accumulator 结构用于存储单个键的相关信息 type Accumulator struct { sync.Mutex // 用于同步访问累加器 window *list.List // 双向链表,用于存储时间窗口内的值 total float64 // 窗口内的总增加量 max float64 // 窗口内的最大值 min float64 // 窗口内的最小值 windowSize time.Duration // 窗口大小 } // NewAccumulator 创建一个新的增加量累加器实例 func NewAccumulator(windowSize time.Duration) *Accumulator { return &Accumulator{ window: list.New(), windowSize: windowSize, max: math.Inf(-1), min: math.Inf(1), } } // AddAcc 增加一个新的值到累加器 func (acc *Accumulator) AddAcc(value float64, timestamp time.Time) { acc.Lock() defer acc.Unlock() // 创建一个新的节点存储增加值和时间戳 _ = acc.window.PushFront(struct { Value float64 Timestamp time.Time }{Value: value, Timestamp: timestamp}) acc.total += value // 移除过期项(超过时间窗口的项) now := time.Now() for e := acc.window.Back(); e != nil; { entry := e.Value.(struct { Value float64 Timestamp time.Time }) if now.Sub(entry.Timestamp) > acc.windowSize { acc.total -= entry.Value next := e.Prev() acc.window.Remove(e) e = next } else { break } } } // MaxAcc 增加一个新的值到累加器 func (acc *Accumulator) MaxAcc(value float64, timestamp time.Time) { acc.Lock() defer acc.Unlock() // 创建一个新的节点存储增加值和时间戳 _ = acc.window.PushFront(struct { Value float64 Timestamp time.Time }{Value: value, Timestamp: timestamp}) if value > acc.max { acc.max = value } // 移除过期项(超过时间窗口的项) now := time.Now() for e := acc.window.Back(); e != nil; { oldEntry := e.Value.(struct { Value float64 Timestamp time.Time }) if now.Sub(oldEntry.Timestamp) > acc.windowSize { acc.total -= oldEntry.Value // 检查移除的项是否是当前最大值,如果是则需要重新计算最大值 if oldEntry.Value == acc.max { acc.recalculateMaxValue() } next := e.Prev() acc.window.Remove(e) e = next } else { break } } } // recalculateMaxValue 重新计算当前时间窗口内的最大值 func (acc *Accumulator) recalculateMaxValue() { // 负无穷大 var maxValue = math.Inf(-1) for e := acc.window.Front(); e != nil; e = e.Next() { entry := e.Value.(struct { Value float64 Timestamp time.Time }) if entry.Value > maxValue { maxValue = entry.Value } } acc.max = maxValue // 更新累加器中的最大值 } // MinAcc 增加一个新的值到累加器 func (acc *Accumulator) MinAcc(value float64, timestamp time.Time) { acc.Lock() defer acc.Unlock() // 创建一个新的节点存储增加值和时间戳 _ = acc.window.PushFront(struct { Value float64 Timestamp time.Time }{Value: value, Timestamp: timestamp}) if value < acc.min { acc.min = value } // 移除过期项(超过时间窗口的项) now := time.Now() for e := acc.window.Back(); e != nil; { oldEntry := e.Value.(struct { Value float64 Timestamp time.Time }) if now.Sub(oldEntry.Timestamp) > acc.windowSize { acc.total -= oldEntry.Value // 检查移除的项是否是当前最大值,如果是则需要重新计算最小值 if oldEntry.Value == acc.min { acc.recalculateMinValue() } next := e.Prev() acc.window.Remove(e) e = next } else { break } } } // recalculateMaxValue 重新计算当前时间窗口内的最小值 func (acc *Accumulator) recalculateMinValue() { // 正无穷大 var minValue = math.Inf(1) for e := acc.window.Front(); e != nil; e = e.Next() { entry := e.Value.(struct { Value float64 Timestamp time.Time }) if entry.Value < minValue { minValue = entry.Value } } acc.min = minValue // 更新累加器中的最小值 } // GetMaxValue 获取当前时间窗口内的最大值 func (acc *Accumulator) GetMaxValue() float64 { acc.Lock() defer acc.Unlock() return acc.max } // GetMinValue 获取当前时间窗口内的最小值 func (acc *Accumulator) GetMinValue() float64 { acc.Lock() defer acc.Unlock() return acc.min } // GetTotalIncrease 获取当前时间窗口内的总增加量 func (acc *Accumulator) GetTotalIncrease() float64 { acc.Lock() defer acc.Unlock() return acc.total } // AccumulatorsMap 存储不同键的累加器Map type AccumulatorsMap struct { sync.RWMutex accumulators map[string]*Accumulator windowSize time.Duration } // NewAccumulatorsMap 创建一个新的时间窗口实例 func NewAccumulatorsMap(windowSize time.Duration) *AccumulatorsMap { return &AccumulatorsMap{ accumulators: make(map[string]*Accumulator), windowSize: windowSize, } } // AddAccMap 增加一个新的值到累加器 func (am *AccumulatorsMap) AddAccMap(key string, value float64) { am.Lock() acc, exists := am.accumulators[key] if !exists { acc = NewAccumulator(am.windowSize) am.accumulators[key] = acc } am.Unlock() acc.AddAcc(value, time.Now()) } // MaxAccMap 增加一个新的值到累加器 func (am *AccumulatorsMap) MaxAccMap(key string, value float64) { am.Lock() acc, exists := am.accumulators[key] if !exists { acc = NewAccumulator(am.windowSize) am.accumulators[key] = acc } am.Unlock() acc.MaxAcc(value, time.Now()) } // MinAccMap 增加一个新的值到累加器 func (am *AccumulatorsMap) MinAccMap(key string, value float64) { am.Lock() acc, exists := am.accumulators[key] if !exists { acc = NewAccumulator(am.windowSize) am.accumulators[key] = acc } am.Unlock() acc.MinAcc(value, time.Now()) } // GetTotalIncrease 获取key的当前时间窗口内的总增加量 func (am *AccumulatorsMap) GetTotalIncrease(key string) float64 { am.RLock() acc, exists := am.accumulators[key] am.RUnlock() if exists { return acc.GetTotalIncrease() } return 0 } // GetMax 获取key的当前时间窗口内的最大值 func (am *AccumulatorsMap) GetMax(key string) float64 { am.RLock() acc, exists := am.accumulators[key] am.RUnlock() if exists { return acc.GetMaxValue() } return 0 } // GetMin 获取key的当前时间窗口内的最小值 func (am *AccumulatorsMap) GetMin(key string) float64 { am.RLock() acc, exists := am.accumulators[key] am.RUnlock() if exists { return acc.GetMinValue() } return 0 }
未经允许 禁止转载