4 Commits

7 changed files with 14 additions and 30 deletions

View File

@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2025 肖其顿 Copyright 2025 肖其顿 (XIAO QI DUN)
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

16
NOTICE
View File

@@ -1,13 +1,5 @@
Copyright 2025 肖其顿 limit
Copyright 2025 肖其顿 (XIAO QI DUN)
Licensed under the Apache License, Version 2.0 (the "License"); This product includes software developed by
you may not use this file except in compliance with the License. 肖其顿 (XIAO QI DUN) (https://github.com/xiaoqidun/limit).
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -1,4 +1,4 @@
// Copyright 2025 肖其顿 // Copyright 2025 肖其顿 (XIAO QI DUN)
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.

4
go.mod
View File

@@ -1,5 +1,5 @@
module github.com/xiaoqidun/limit module github.com/xiaoqidun/limit
go 1.25.1 go 1.25.3
require golang.org/x/time v0.13.0 require golang.org/x/time v0.14.0

4
go.sum
View File

@@ -1,2 +1,2 @@
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=

View File

@@ -1,4 +1,4 @@
// Copyright 2025 肖其顿 // Copyright 2025 肖其顿 (XIAO QI DUN)
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -69,17 +69,14 @@ func NewWithConfig(config Config) *Limiter {
if config.Expiration == 0 { if config.Expiration == 0 {
config.Expiration = 30 * time.Minute config.Expiration = 30 * time.Minute
} }
// 确保分片数量是2的幂以便进行高效的位运算 // 确保分片数量是2的幂以便进行高效的位运算
if config.ShardCount <= 0 || (config.ShardCount&(config.ShardCount-1)) != 0 { if config.ShardCount <= 0 || (config.ShardCount&(config.ShardCount-1)) != 0 {
config.ShardCount = defaultShardCount config.ShardCount = defaultShardCount
} }
l := &Limiter{ l := &Limiter{
shards: make([]*shard, config.ShardCount), shards: make([]*shard, config.ShardCount),
config: config, config: config,
} }
// 初始化所有分片 // 初始化所有分片
for i := 0; i < config.ShardCount; i++ { for i := 0; i < config.ShardCount; i++ {
l.shards[i] = newShard(config.GCInterval, config.Expiration) l.shards[i] = newShard(config.GCInterval, config.Expiration)
@@ -166,7 +163,6 @@ func (s *shard) gc(interval, expiration time.Duration) {
return return
default: default:
} }
select { select {
case <-ticker.C: case <-ticker.C:
s.mutex.Lock() s.mutex.Lock()
@@ -239,20 +235,16 @@ func (s *shard) stop() {
s.stopOnce.Do(func() { s.stopOnce.Do(func() {
close(s.stopCh) close(s.stopCh)
}) })
// 等待 gc goroutine 完全退出 // 等待 gc goroutine 完全退出
s.waitGroup.Wait() s.waitGroup.Wait()
// 锁定并进行最终的资源清理 // 锁定并进行最终的资源清理
// 因为 gc 已经退出,所以此时只有 Get/Del 会竞争锁 // 因为 gc 已经退出,所以此时只有 Get/Del 会竞争锁
s.mutex.Lock() s.mutex.Lock()
defer s.mutex.Unlock() defer s.mutex.Unlock()
// 检查是否已被清理,防止重复操作 // 检查是否已被清理,防止重复操作
if s.limiter == nil { if s.limiter == nil {
return return
} }
// 将所有 session 对象放回对象池 // 将所有 session 对象放回对象池
for _, sess := range s.limiter { for _, sess := range s.limiter {
sess.limiter = nil sess.limiter = nil
@@ -273,14 +265,14 @@ type session struct {
// sessionPool 使用 sync.Pool 来复用 session 对象,以减少 GC 压力。 // sessionPool 使用 sync.Pool 来复用 session 对象,以减少 GC 压力。
var sessionPool = sync.Pool{ var sessionPool = sync.Pool{
New: func() interface{} { New: func() any {
return new(session) return new(session)
}, },
} }
// fnvHasherPool 使用 sync.Pool 来复用 FNV-1a 哈希对象,以减少高并发下的内存分配。 // fnvHasherPool 使用 sync.Pool 来复用 FNV-1a 哈希对象,以减少高并发下的内存分配。
var fnvHasherPool = sync.Pool{ var fnvHasherPool = sync.Pool{
New: func() interface{} { New: func() any {
return fnv.New32a() return fnv.New32a()
}, },
} }

View File

@@ -1,4 +1,4 @@
// Copyright 2025 肖其顿 // Copyright 2025 肖其顿 (XIAO QI DUN)
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.