Skip to content

Commit f2c3a83

Browse files
committed
feat: 添加基于 xsync.UMPSCQueue[T] 高性能 queue 包
1 parent 2f44f8d commit f2c3a83

4 files changed

Lines changed: 282 additions & 20 deletions

File tree

go.mod

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ require (
1515
github.com/gin-gonic/gin v1.11.0
1616
github.com/go-cmd/cmd v1.4.3
1717
github.com/goccy/go-json v0.10.5
18-
github.com/gofiber/fiber/v3 v3.0.0
18+
github.com/gofiber/fiber/v3 v3.1.0
1919
github.com/imroc/req/v3 v3.57.0
2020
github.com/jedib0t/go-pretty/v6 v6.7.8
2121
github.com/joho/godotenv v1.5.1
2222
github.com/natefinch/lumberjack/v3 v3.0.0-alpha
23-
github.com/redis/go-redis/v9 v9.17.3
23+
github.com/redis/go-redis/v9 v9.18.0
2424
github.com/rs/zerolog v1.34.0
2525
github.com/shirou/gopsutil/v3 v3.24.5
2626
golang.org/x/sync v0.19.0
@@ -32,7 +32,7 @@ require (
3232
github.com/bytedance/sonic v1.15.0 // indirect
3333
github.com/bytedance/sonic/loader v0.5.0 // indirect
3434
github.com/cespare/xxhash/v2 v2.3.0 // indirect
35-
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
35+
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
3636
github.com/cloudwego/base64x v0.1.6 // indirect
3737
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
3838
github.com/gabriel-vasile/mimetype v1.4.13 // indirect
@@ -44,7 +44,7 @@ require (
4444
github.com/go-redis/redis/v8 v8.11.5 // indirect
4545
github.com/goccy/go-yaml v1.19.2 // indirect
4646
github.com/gofiber/schema v1.7.0 // indirect
47-
github.com/gofiber/utils/v2 v2.0.1 // indirect
47+
github.com/gofiber/utils/v2 v2.0.2 // indirect
4848
github.com/google/go-querystring v1.2.0 // indirect
4949
github.com/google/uuid v1.6.0 // indirect
5050
github.com/icholy/digest v1.1.0 // indirect
@@ -53,10 +53,10 @@ require (
5353
github.com/klauspost/compress v1.18.4 // indirect
5454
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
5555
github.com/leodido/go-urn v1.4.0 // indirect
56-
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 // indirect
56+
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 // indirect
5757
github.com/mattn/go-colorable v0.1.14 // indirect
5858
github.com/mattn/go-isatty v0.0.20 // indirect
59-
github.com/mattn/go-runewidth v0.0.19 // indirect
59+
github.com/mattn/go-runewidth v0.0.20 // indirect
6060
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
6161
github.com/modern-go/reflect2 v1.0.2 // indirect
6262
github.com/onsi/gomega v1.36.3 // indirect
@@ -75,6 +75,7 @@ require (
7575
github.com/valyala/bytebufferpool v1.0.0 // indirect
7676
github.com/valyala/fasthttp v1.69.0 // indirect
7777
github.com/yusufpapurcu/wmi v1.2.4 // indirect
78+
go.uber.org/atomic v1.11.0 // indirect
7879
golang.org/x/arch v0.24.0 // indirect
7980
golang.org/x/crypto v0.48.0 // indirect
8081
golang.org/x/net v0.50.0 // indirect

go.sum

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ github.com/chenyahui/gin-cache v1.10.0/go.mod h1:7yoxLlCM6TEbvaSzW3p04Zg4IviY3x5
1818
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
1919
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
2020
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
21-
github.com/clipperhouse/uax29/v2 v2.6.0 h1:z0cDbUV+aPASdFb2/ndFnS9ts/WNXgTNNGFoKXuhpos=
22-
github.com/clipperhouse/uax29/v2 v2.6.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
21+
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
22+
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
2323
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
2424
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
2525
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
@@ -84,12 +84,12 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
8484
github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
8585
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
8686
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
87-
github.com/gofiber/fiber/v3 v3.0.0 h1:GPeCG8X60L42wLKrzgeewDHBr6pE6veAvwaXsqD3Xjk=
88-
github.com/gofiber/fiber/v3 v3.0.0/go.mod h1:kVZiO/AwyT5Pq6PgC8qRCJ+j/BHrMy5jNw1O9yH38aY=
87+
github.com/gofiber/fiber/v3 v3.1.0 h1:1p4I820pIa+FGxfwWuQZ5rAyX0WlGZbGT6Hnuxt6hKY=
88+
github.com/gofiber/fiber/v3 v3.1.0/go.mod h1:n2nYQovvL9z3Too/FGOfgtERjW3GQcAUqgfoezGBZdU=
8989
github.com/gofiber/schema v1.7.0 h1:yNM+FNRZjyYEli9Ey0AXRBrAY9jTnb+kmGs3lJGPvKg=
9090
github.com/gofiber/schema v1.7.0/go.mod h1:A/X5Ffyru4p9eBdp99qu+nzviHzQiZ7odLT+TwxWhbk=
91-
github.com/gofiber/utils/v2 v2.0.1 h1:+kvhvoGuAeUBzF/Qlkx5HvFK7tNd62mxSpBuI0zCRII=
92-
github.com/gofiber/utils/v2 v2.0.1/go.mod h1:xF9v89FfmbrYqI/bQUGN7gR8ZtXot2jxnZvmAUtiavE=
91+
github.com/gofiber/utils/v2 v2.0.2 h1:ShRRssz0F3AhTlAQcuEj54OEDtWF7+HJDwEi/aa6QLI=
92+
github.com/gofiber/utils/v2 v2.0.2/go.mod h1:+9Ub4NqQ+IaJoTliq5LfdmOJAA/Hzwf4pXOxOa3RrJ0=
9393
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
9494
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
9595
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
@@ -138,8 +138,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
138138
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
139139
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
140140
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
141-
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3 h1:PwQumkgq4/acIiZhtifTV5OUqqiP82UAl0h87xj/l9k=
142-
github.com/lufia/plan9stats v0.0.0-20251013123823-9fd1530e3ec3/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
141+
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88 h1:PTw+yKnXcOFCR6+8hHTyWBeQ/P4Nb7dd4/0ohEcWQuM=
142+
github.com/lufia/plan9stats v0.0.0-20260216142805-b3301c5f2a88/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
143143
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
144144
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
145145
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
@@ -148,8 +148,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
148148
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
149149
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
150150
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
151-
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
152-
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
151+
github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ=
152+
github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
153153
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
154154
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
155155
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -186,15 +186,15 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
186186
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
187187
github.com/quic-go/quic-go v0.58.0 h1:ggY2pvZaVdB9EyojxL1p+5mptkuHyX5MOSv4dgWF4Ug=
188188
github.com/quic-go/quic-go v0.58.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
189-
github.com/redis/go-redis/v9 v9.17.3 h1:fN29NdNrE17KttK5Ndf20buqfDZwGNgoUr9qjl1DQx4=
190-
github.com/redis/go-redis/v9 v9.17.3/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
189+
github.com/redis/go-redis/v9 v9.18.0 h1:pMkxYPkEbMPwRdenAzUNyFNrDgHx9U+DrBabWNfSRQs=
190+
github.com/redis/go-redis/v9 v9.18.0/go.mod h1:k3ufPphLU5YXwNTUcCRXGxUoF1fqxnhFQmscfkCoDA0=
191191
github.com/refraction-networking/utls v1.8.1 h1:yNY1kapmQU8JeM1sSw2H2asfTIwWxIkrMJI0pRUOCAo=
192192
github.com/refraction-networking/utls v1.8.1/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
193193
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
194194
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
195195
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
196-
github.com/shamaton/msgpack/v3 v3.0.0 h1:xl40uxWkSpwBCSTvS5wyXvJRsC6AcVcYeox9PspKiZg=
197-
github.com/shamaton/msgpack/v3 v3.0.0/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc=
196+
github.com/shamaton/msgpack/v3 v3.1.0 h1:jsk0vEAqVvvS9+fTZ5/EcQ9tz860c9pWxJ4Iwecz8gU=
197+
github.com/shamaton/msgpack/v3 v3.1.0/go.mod h1:DcQG8jrdrQCIxr3HlMYkiXdMhK+KfN2CitkyzsQV4uc=
198198
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
199199
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
200200
github.com/shoenig/go-m1cpu v0.1.7 h1:C76Yd0ObKR82W4vhfjZiCp0HxcSZ8Nqd84v+HZ0qyI0=
@@ -238,6 +238,10 @@ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3i
238238
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
239239
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
240240
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
241+
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
242+
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
243+
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
244+
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
241245
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
242246
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
243247
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=

queue/queue.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package queue
2+
3+
import (
4+
"github.com/fufuok/cache/xsync"
5+
6+
"github.com/fufuok/pkg/kit"
7+
)
8+
9+
// Queue 封装了 UMPSCQueue 和计数器
10+
type Queue[T any] struct {
11+
queue *xsync.UMPSCQueue[T]
12+
queueRate *kit.RateState
13+
enqueueCount *kit.UCounter
14+
dequeueCount *kit.UCounter
15+
}
16+
17+
// New 创建一个新的 Queue 实例
18+
func New[T any]() *Queue[T] {
19+
return &Queue[T]{
20+
queue: xsync.NewUMPSCQueue[T](),
21+
queueRate: kit.NewRateState(),
22+
enqueueCount: kit.NewUCounter(),
23+
dequeueCount: kit.NewUCounter(),
24+
}
25+
}
26+
27+
// Enqueue 向队列中添加数据并更新计数器 (多生产者: 安全)
28+
func (q *Queue[T]) Enqueue(value T) {
29+
q.enqueueCount.Add(1)
30+
q.queue.Enqueue(value)
31+
}
32+
33+
// Dequeue 从队列中获取数据并更新计数器 (仅单消费者!!!)
34+
func (q *Queue[T]) Dequeue() T {
35+
value := q.queue.Dequeue()
36+
q.dequeueCount.Add(1)
37+
return value
38+
}
39+
40+
// Len 返回当前队列长度
41+
func (q *Queue[T]) Len() uint64 {
42+
enq := q.enqueueCount.Load()
43+
deq := q.dequeueCount.Load()
44+
if enq < deq {
45+
return 0
46+
}
47+
return enq - deq
48+
}
49+
50+
// RateState 返回入队速率, 当前计数, 上一次计数
51+
func (q *Queue[T]) RateState() (rate float64, enqueueCount, lastEnqueueCount uint64) {
52+
enqueueCount = q.enqueueCount.Load()
53+
rate, lastEnqueueCount = q.queueRate.RateWithLastCount(q.enqueueCount.Load())
54+
return
55+
}

queue/queue_test.go

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package queue
2+
3+
import (
4+
"sync"
5+
"testing"
6+
"time"
7+
)
8+
9+
// TestQueue_Basic 测试队列基本操作
10+
func TestQueue_Basic(t *testing.T) {
11+
q := New[int]()
12+
13+
// 测试入队
14+
q.Enqueue(1)
15+
q.Enqueue(2)
16+
q.Enqueue(3)
17+
18+
// 测试长度
19+
if l := q.Len(); l != 3 {
20+
t.Errorf("Expected length 3, got %d", l)
21+
}
22+
23+
// 测试出队
24+
if v := q.Dequeue(); v != 1 {
25+
t.Errorf("Expected 1, got %d", v)
26+
}
27+
if v := q.Dequeue(); v != 2 {
28+
t.Errorf("Expected 2, got %d", v)
29+
}
30+
if v := q.Dequeue(); v != 3 {
31+
t.Errorf("Expected 3, got %d", v)
32+
}
33+
34+
// 测试长度
35+
if l := q.Len(); l != 0 {
36+
t.Errorf("Expected length 0, got %d", l)
37+
}
38+
}
39+
40+
// TestQueue_EmptyDequeue 测试空队列出队(应该阻塞)
41+
func TestQueue_EmptyDequeue(t *testing.T) {
42+
q := New[int]()
43+
44+
// 启动一个goroutine入队
45+
go func() {
46+
time.Sleep(100 * time.Millisecond)
47+
q.Enqueue(42)
48+
}()
49+
50+
// 测试出队(应该等待并成功获取值)
51+
start := time.Now()
52+
v := q.Dequeue()
53+
duration := time.Since(start)
54+
55+
if v != 42 {
56+
t.Errorf("Expected 42, got %d", v)
57+
}
58+
59+
// 确保出队操作等待了一段时间(证明阻塞了)
60+
if duration < 50*time.Millisecond {
61+
t.Errorf("Dequeue should have blocked, but completed too quickly: %v", duration)
62+
}
63+
}
64+
65+
// TestQueue_Len 测试队列长度计算
66+
func TestQueue_Len(t *testing.T) {
67+
q := New[string]()
68+
69+
// 空队列
70+
if l := q.Len(); l != 0 {
71+
t.Errorf("Expected length 0, got %d", l)
72+
}
73+
74+
// 入队一个元素
75+
q.Enqueue("test1")
76+
if l := q.Len(); l != 1 {
77+
t.Errorf("Expected length 1, got %d", l)
78+
}
79+
80+
// 入队多个元素
81+
q.Enqueue("test2")
82+
q.Enqueue("test3")
83+
if l := q.Len(); l != 3 {
84+
t.Errorf("Expected length 3, got %d", l)
85+
}
86+
87+
// 出队一个元素
88+
q.Dequeue()
89+
if l := q.Len(); l != 2 {
90+
t.Errorf("Expected length 2, got %d", l)
91+
}
92+
93+
// 出队所有元素
94+
q.Dequeue()
95+
q.Dequeue()
96+
if l := q.Len(); l != 0 {
97+
t.Errorf("Expected length 0, got %d", l)
98+
}
99+
}
100+
101+
// TestQueue_RateState 测试速率统计
102+
func TestQueue_RateState(t *testing.T) {
103+
q := New[int]()
104+
105+
// 初始状态
106+
_, count, lastCount := q.RateState()
107+
if count != 0 {
108+
t.Errorf("Expected initial count 0, got %d", count)
109+
}
110+
if lastCount != 0 {
111+
t.Errorf("Expected initial lastCount 0, got %d", lastCount)
112+
}
113+
114+
// 入队一些元素
115+
for i := 0; i < 10; i++ {
116+
q.Enqueue(i)
117+
}
118+
119+
// 测试速率统计
120+
_, count, lastCount = q.RateState()
121+
if count != 10 {
122+
t.Errorf("Expected count 10, got %d", count)
123+
}
124+
125+
// 等待一段时间后再次测试速率
126+
time.Sleep(100 * time.Millisecond)
127+
_, count, lastCount = q.RateState()
128+
if count != 10 {
129+
t.Errorf("Expected count still 10, got %d", count)
130+
}
131+
}
132+
133+
// TestQueue_Concurrent 测试并发场景
134+
func TestQueue_Concurrent(t *testing.T) {
135+
q := New[int]()
136+
var wg sync.WaitGroup
137+
138+
// 启动多个生产者
139+
producerCount := 5
140+
itemsPerProducer := 100
141+
totalItems := producerCount * itemsPerProducer
142+
143+
for i := 0; i < producerCount; i++ {
144+
wg.Add(1)
145+
go func(producerID int) {
146+
defer wg.Done()
147+
for j := 0; j < itemsPerProducer; j++ {
148+
q.Enqueue(producerID*itemsPerProducer + j)
149+
}
150+
}(i)
151+
}
152+
153+
// 启动消费者
154+
var consumerWg sync.WaitGroup
155+
consumerWg.Add(1)
156+
received := make(map[int]bool)
157+
go func() {
158+
defer consumerWg.Done()
159+
for i := 0; i < totalItems; i++ {
160+
v := q.Dequeue()
161+
received[v] = true
162+
}
163+
}()
164+
165+
// 等待所有生产者完成
166+
wg.Wait()
167+
168+
// 等待消费者完成
169+
consumerWg.Wait()
170+
171+
// 验证所有项目都被正确接收
172+
if len(received) != totalItems {
173+
t.Errorf("Expected to receive %d items, got %d", totalItems, len(received))
174+
}
175+
176+
// 验证队列长度为0
177+
if l := q.Len(); l != 0 {
178+
t.Errorf("Expected length 0 after all operations, got %d", l)
179+
}
180+
}
181+
182+
// TestQueue_GenericTypes 测试泛型类型
183+
func TestQueue_GenericTypes(t *testing.T) {
184+
// 测试字符串类型
185+
stringQueue := New[string]()
186+
stringQueue.Enqueue("hello")
187+
if v := stringQueue.Dequeue(); v != "hello" {
188+
t.Errorf("Expected 'hello', got '%s'", v)
189+
}
190+
191+
// 测试结构体类型
192+
type TestStruct struct {
193+
Value int
194+
Name string
195+
}
196+
structQueue := New[TestStruct]()
197+
testStruct := TestStruct{Value: 42, Name: "test"}
198+
structQueue.Enqueue(testStruct)
199+
if v := structQueue.Dequeue(); v != testStruct {
200+
t.Errorf("Expected %+v, got %+v", testStruct, v)
201+
}
202+
}

0 commit comments

Comments
 (0)