mirror of
https://github.com/wonli/aqi.git
synced 2025-09-26 12:41:15 +08:00
simple uid
This commit is contained in:
36
utils/uidgen/simple_uid.go
Normal file
36
utils/uidgen/simple_uid.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package uidgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 全局原子计数器
|
||||
var counter uint64
|
||||
|
||||
// GenId 并发安全的生成 16 位整型ID
|
||||
func GenId() int64 {
|
||||
idStr := GenSid()
|
||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
||||
return id
|
||||
}
|
||||
|
||||
// GenSid 并发安全的生成 16 位字符串ID
|
||||
func GenSid() string {
|
||||
now := time.Now()
|
||||
yearPart := 100 + (now.Year() - 2025)
|
||||
dayPart := now.YearDay() + 521
|
||||
secsOfDay := now.Hour()*3600 + now.Minute()*60 + now.Second()
|
||||
|
||||
subSecondPart := now.Nanosecond() / 1e5
|
||||
base := uint64(secsOfDay)*100000 + uint64(subSecondPart)
|
||||
seq := atomic.AddUint64(&counter, 1)
|
||||
if seq < base {
|
||||
atomic.CompareAndSwapUint64(&counter, seq, base)
|
||||
seq = base
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%03d%03d%010d", yearPart, dayPart, seq)
|
||||
}
|
980
utils/uidgen/simple_uid_test.go
Normal file
980
utils/uidgen/simple_uid_test.go
Normal file
@@ -0,0 +1,980 @@
|
||||
package uidgen
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
func TestGenerateID(t *testing.T) {
|
||||
ddd := map[int64]bool{}
|
||||
|
||||
for i := 0; i < 800000; i++ {
|
||||
tid := GenId()
|
||||
lll := len(cast.ToString(tid))
|
||||
if ddd[tid] || lll != 16 {
|
||||
t.Errorf("测试失败")
|
||||
log.Println(tid, " -- ", len(cast.ToString(tid)))
|
||||
} else {
|
||||
ddd[tid] = true
|
||||
}
|
||||
}
|
||||
|
||||
log.Println(len(ddd))
|
||||
}
|
||||
|
||||
func TestConcurrentGenId(t *testing.T) {
|
||||
const goroutines = 1000
|
||||
const iterations = 100
|
||||
|
||||
results := make(chan int64, goroutines*iterations)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
log.Printf("开始高并发测试: %d个goroutine,每个生成%d个ID\n", goroutines, iterations)
|
||||
start := time.Now()
|
||||
|
||||
// 真正的高并发测试
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
results <- GenId()
|
||||
// 不要sleep,保持真正的并发压力
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
duration := time.Since(start)
|
||||
log.Printf("生成完成,耗时: %v\n", duration)
|
||||
|
||||
// 检查重复和长度
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
invalidLength := 0
|
||||
total := 0
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
t.Errorf("发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
|
||||
idStr := cast.ToString(id)
|
||||
if len(idStr) != 16 {
|
||||
invalidLength++
|
||||
t.Errorf("ID长度不正确: %d (长度: %d)", id, len(idStr))
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("测试结果统计:\n")
|
||||
log.Printf("- 总生成数量: %d\n", total)
|
||||
log.Printf("- 唯一ID数量: %d\n", len(seen))
|
||||
log.Printf("- 重复ID数量: %d\n", duplicates)
|
||||
log.Printf("- 长度错误数量: %d\n", invalidLength)
|
||||
log.Printf("- 生成速率: %.2f ID/秒\n", float64(total)/duration.Seconds())
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("发现 %d 个重复ID,测试失败!", duplicates)
|
||||
}
|
||||
|
||||
if invalidLength > 0 {
|
||||
t.Fatalf("发现 %d 个长度错误的ID,测试失败!", invalidLength)
|
||||
}
|
||||
}
|
||||
|
||||
// 跨秒边界测试
|
||||
func TestCrossSecondBoundary(t *testing.T) {
|
||||
log.Println("开始跨秒边界测试...")
|
||||
|
||||
// 等待接近下一秒
|
||||
now := time.Now()
|
||||
nextSecond := now.Truncate(time.Second).Add(time.Second)
|
||||
time.Sleep(time.Until(nextSecond.Add(-100 * time.Millisecond)))
|
||||
|
||||
const goroutines = 500
|
||||
results := make(chan int64, goroutines)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 在秒边界附近启动大量goroutine
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
results <- GenId()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
t.Errorf("跨秒边界测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("跨秒边界测试结果: 总数=%d, 唯一=%d, 重复=%d\n", total, len(seen), duplicates)
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("跨秒边界测试发现 %d 个重复ID!", duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 极限压力测试
|
||||
func TestExtremeStress(t *testing.T) {
|
||||
const goroutines = 5000
|
||||
const iterations = 200
|
||||
|
||||
log.Printf("开始极限压力测试: %d个goroutine,每个生成%d个ID\n", goroutines, iterations)
|
||||
start := time.Now()
|
||||
|
||||
results := make(chan int64, goroutines*iterations)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < iterations; j++ {
|
||||
results <- GenId()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
duration := time.Since(start)
|
||||
log.Printf("极限压力测试完成,耗时: %v\n", duration)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
t.Errorf("极限压力测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("极限压力测试结果: 总数=%d, 唯一=%d, 重复=%d, 速率=%.2f ID/秒\n",
|
||||
total, len(seen), duplicates, float64(total)/duration.Seconds())
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("极限压力测试发现 %d 个重复ID!", duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 同一毫秒内的超高并发测试
|
||||
func TestSameMillisecondConcurrency(t *testing.T) {
|
||||
log.Println("开始同一毫秒内超高并发测试...")
|
||||
|
||||
const goroutines = 10000
|
||||
results := make(chan int64, goroutines)
|
||||
var wg sync.WaitGroup
|
||||
var startSignal sync.WaitGroup
|
||||
startSignal.Add(1)
|
||||
|
||||
// 预先启动所有goroutine,等待信号同时开始
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startSignal.Wait() // 等待开始信号
|
||||
results <- GenId()
|
||||
}()
|
||||
}
|
||||
|
||||
// 短暂延迟后同时释放所有goroutine
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
startSignal.Done()
|
||||
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
t.Errorf("同一毫秒测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("同一毫秒测试结果: 总数=%d, 唯一=%d, 重复=%d\n", total, len(seen), duplicates)
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("同一毫秒测试发现 %d 个重复ID!", duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 超极限压力测试 - 挑战单秒10万次限制
|
||||
func TestUltraExtremeStress(t *testing.T) {
|
||||
const goroutines = 20000
|
||||
const iterations = 10
|
||||
|
||||
log.Printf("开始超极限压力测试: %d个goroutine,每个生成%d个ID (总计%d个)\n",
|
||||
goroutines, iterations, goroutines*iterations)
|
||||
start := time.Now()
|
||||
|
||||
results := make(chan int64, goroutines*iterations)
|
||||
var wg sync.WaitGroup
|
||||
var startSignal sync.WaitGroup
|
||||
startSignal.Add(1)
|
||||
|
||||
// 预先启动所有goroutine,等待信号同时开始
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startSignal.Wait() // 等待开始信号
|
||||
for j := 0; j < iterations; j++ {
|
||||
results <- GenId()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 同时释放所有goroutine,制造极端并发
|
||||
startSignal.Done()
|
||||
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
duration := time.Since(start)
|
||||
log.Printf("超极限压力测试完成,耗时: %v\n", duration)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("超极限压力测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("超极限压力测试结果: 总数=%d, 唯一=%d, 重复=%d, 速率=%.2f ID/秒\n",
|
||||
total, len(seen), duplicates, float64(total)/duration.Seconds())
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表: %v\n", duplicateIds[:min(len(duplicateIds), 10)])
|
||||
}
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("超极限压力测试发现 %d 个重复ID!", duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 连续秒边界冲击测试
|
||||
func TestContinuousSecondBoundaryStress(t *testing.T) {
|
||||
log.Println("开始连续秒边界冲击测试...")
|
||||
|
||||
const rounds = 5
|
||||
const goroutinesPerRound = 5000
|
||||
allResults := make([]int64, 0, rounds*goroutinesPerRound)
|
||||
var mu sync.Mutex
|
||||
|
||||
for round := 0; round < rounds; round++ {
|
||||
log.Printf("第 %d 轮秒边界测试\n", round+1)
|
||||
|
||||
// 等待接近下一秒
|
||||
now := time.Now()
|
||||
nextSecond := now.Truncate(time.Second).Add(time.Second)
|
||||
time.Sleep(time.Until(nextSecond.Add(-50 * time.Millisecond)))
|
||||
|
||||
results := make(chan int64, goroutinesPerRound)
|
||||
var wg sync.WaitGroup
|
||||
var startSignal sync.WaitGroup
|
||||
startSignal.Add(1)
|
||||
|
||||
// 在秒边界附近启动大量goroutine
|
||||
for i := 0; i < goroutinesPerRound; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startSignal.Wait()
|
||||
results <- GenId()
|
||||
}()
|
||||
}
|
||||
|
||||
startSignal.Done()
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
// 收集结果
|
||||
mu.Lock()
|
||||
for id := range results {
|
||||
allResults = append(allResults, id)
|
||||
}
|
||||
mu.Unlock()
|
||||
}
|
||||
|
||||
// 检查所有轮次的重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for _, id := range allResults {
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("连续秒边界测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("连续秒边界测试结果: 总数=%d, 唯一=%d, 重复=%d\n",
|
||||
len(allResults), len(seen), duplicates)
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表: %v\n", duplicateIds[:min(len(duplicateIds), 10)])
|
||||
}
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("连续秒边界测试发现 %d 个重复ID!", duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 长时间持续压力测试
|
||||
func TestLongRunningStress(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("跳过长时间测试")
|
||||
}
|
||||
|
||||
log.Println("开始长时间持续压力测试 (5秒)...")
|
||||
|
||||
const duration = 5 * time.Second
|
||||
const goroutines = 1000
|
||||
|
||||
results := make(chan int64, 1000000) // 预分配大缓冲区
|
||||
var wg sync.WaitGroup
|
||||
stop := make(chan struct{})
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// 启动持续生成ID的goroutine
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
case results <- GenId():
|
||||
time.Sleep(time.Microsecond) // 微小延迟避免CPU占用过高
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 运行指定时间后停止
|
||||
time.Sleep(duration)
|
||||
close(stop)
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
actualDuration := time.Since(start)
|
||||
log.Printf("长时间测试完成,实际耗时: %v\n", actualDuration)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("长时间测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("长时间测试结果: 总数=%d, 唯一=%d, 重复=%d, 平均速率=%.2f ID/秒\n",
|
||||
total, len(seen), duplicates, float64(total)/actualDuration.Seconds())
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表: %v\n", duplicateIds[:min(len(duplicateIds), 10)])
|
||||
}
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("长时间测试发现 %d 个重复ID!", duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 单秒内超过10万次调用的极限测试
|
||||
func TestExceedSingleSecondLimit(t *testing.T) {
|
||||
log.Println("开始单秒内超过10万次调用的极限测试...")
|
||||
|
||||
// 目标:在1秒内生成超过10万个ID
|
||||
const targetIds = 150000
|
||||
const maxGoroutines = 50000
|
||||
const idsPerGoroutine = targetIds / maxGoroutines
|
||||
|
||||
log.Printf("目标生成 %d 个ID,使用 %d 个goroutine,每个生成 %d 个\n",
|
||||
targetIds, maxGoroutines, idsPerGoroutine)
|
||||
|
||||
results := make(chan int64, targetIds)
|
||||
var wg sync.WaitGroup
|
||||
var startSignal sync.WaitGroup
|
||||
startSignal.Add(1)
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// 启动大量goroutine
|
||||
for i := 0; i < maxGoroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startSignal.Wait()
|
||||
for j := 0; j < idsPerGoroutine; j++ {
|
||||
results <- GenId()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// 同时释放所有goroutine
|
||||
startSignal.Done()
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
duration := time.Since(start)
|
||||
log.Printf("极限测试完成,耗时: %v\n", duration)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("单秒极限测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("单秒极限测试结果: 总数=%d, 唯一=%d, 重复=%d, 速率=%.2f ID/秒\n",
|
||||
total, len(seen), duplicates, float64(total)/duration.Seconds())
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表 (前10个): %v\n", duplicateIds[:min(len(duplicateIds), 10)])
|
||||
// 分析重复ID的模式
|
||||
log.Printf("分析重复ID模式...\n")
|
||||
for i, dupId := range duplicateIds[:min(len(duplicateIds), 5)] {
|
||||
idStr := cast.ToString(dupId)
|
||||
log.Printf("重复ID %d: %s (长度: %d)\n", i+1, idStr, len(idStr))
|
||||
}
|
||||
}
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("单秒极限测试发现 %d 个重复ID!这证明了在超高并发下存在唯一性问题", duplicates)
|
||||
} else {
|
||||
log.Printf("✅ 即使在 %.2f ID/秒 的极高速率下,仍然保持了唯一性\n", float64(total)/duration.Seconds())
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟真实业务场景的混合压力测试
|
||||
func TestRealWorldMixedStress(t *testing.T) {
|
||||
log.Println("开始模拟真实业务场景的混合压力测试...")
|
||||
|
||||
const duration = 5 * time.Second
|
||||
const normalGoroutines = 100 // 正常业务goroutine
|
||||
const burstGoroutines = 2000 // 突发流量goroutine
|
||||
const burstInterval = 1 * time.Second // 突发间隔
|
||||
|
||||
results := make(chan int64, 500000)
|
||||
var wg sync.WaitGroup
|
||||
stop := make(chan struct{})
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// 启动正常业务流量
|
||||
for i := 0; i < normalGoroutines; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
default:
|
||||
results <- GenId()
|
||||
time.Sleep(time.Millisecond * time.Duration(10+id%20)) // 模拟不同的业务处理时间
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 定期产生突发流量
|
||||
go func() {
|
||||
ticker := time.NewTicker(burstInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
case <-ticker.C:
|
||||
log.Printf("触发突发流量: %d 个并发请求\n", burstGoroutines)
|
||||
// 突发大量并发请求
|
||||
var burstWg sync.WaitGroup
|
||||
for i := 0; i < burstGoroutines; i++ {
|
||||
burstWg.Add(1)
|
||||
go func() {
|
||||
defer burstWg.Done()
|
||||
results <- GenId()
|
||||
}()
|
||||
}
|
||||
burstWg.Wait()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 运行指定时间
|
||||
time.Sleep(duration)
|
||||
close(stop)
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
actualDuration := time.Since(start)
|
||||
log.Printf("混合压力测试完成,实际耗时: %v\n", actualDuration)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("混合压力测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("混合压力测试结果: 总数=%d, 唯一=%d, 重复=%d, 平均速率=%.2f ID/秒\n",
|
||||
total, len(seen), duplicates, float64(total)/actualDuration.Seconds())
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表: %v\n", duplicateIds[:min(len(duplicateIds), 10)])
|
||||
}
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("混合压力测试发现 %d 个重复ID!", duplicates)
|
||||
} else {
|
||||
log.Printf("✅ 在真实业务场景模拟下保持了唯一性\n")
|
||||
}
|
||||
}
|
||||
|
||||
// 最极端的多核心并发测试
|
||||
func TestExtremeMultiCoreStress(t *testing.T) {
|
||||
log.Println("开始最极端的多核心并发测试...")
|
||||
|
||||
// 获取CPU核心数
|
||||
numCPU := runtime.NumCPU()
|
||||
runtime.GOMAXPROCS(numCPU)
|
||||
log.Printf("使用 %d 个CPU核心\n", numCPU)
|
||||
|
||||
// 每个核心启动合理数量的goroutine
|
||||
const goroutinesPerCore = 1000
|
||||
const idsPerGoroutine = 100
|
||||
totalGoroutines := numCPU * goroutinesPerCore
|
||||
totalIds := totalGoroutines * idsPerGoroutine
|
||||
|
||||
log.Printf("启动 %d 个goroutine (每核心%d个),总共生成 %d 个ID\n",
|
||||
totalGoroutines, goroutinesPerCore, totalIds)
|
||||
|
||||
results := make(chan int64, totalIds)
|
||||
var wg sync.WaitGroup
|
||||
var startSignal sync.WaitGroup
|
||||
startSignal.Add(1)
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// 为每个CPU核心启动goroutine
|
||||
for core := 0; core < numCPU; core++ {
|
||||
for i := 0; i < goroutinesPerCore; i++ {
|
||||
wg.Add(1)
|
||||
go func(coreId, goroutineId int) {
|
||||
defer wg.Done()
|
||||
// 绑定到特定CPU核心(尽力而为)
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
startSignal.Wait()
|
||||
for j := 0; j < idsPerGoroutine; j++ {
|
||||
results <- GenId()
|
||||
// 故意不加任何延迟,最大化并发冲突
|
||||
}
|
||||
}(core, i)
|
||||
}
|
||||
}
|
||||
|
||||
// 同时释放所有goroutine
|
||||
startSignal.Done()
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
duration := time.Since(start)
|
||||
log.Printf("多核心极限测试完成,耗时: %v\n", duration)
|
||||
|
||||
// 检查重复
|
||||
seen := make(map[int64]bool)
|
||||
duplicates := 0
|
||||
total := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for id := range results {
|
||||
total++
|
||||
if seen[id] {
|
||||
duplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("多核心极限测试发现重复ID: %d", id)
|
||||
}
|
||||
seen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("多核心极限测试结果: 总数=%d, 唯一=%d, 重复=%d, 速率=%.2f ID/秒\n",
|
||||
total, len(seen), duplicates, float64(total)/duration.Seconds())
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表 (前10个): %v\n", duplicateIds[:min(len(duplicateIds), 10)])
|
||||
}
|
||||
|
||||
if duplicates > 0 {
|
||||
t.Fatalf("多核心极限测试发现 %d 个重复ID!", duplicates)
|
||||
} else {
|
||||
log.Printf("✅ 在 %d 核心、%.2f ID/秒 的极限条件下仍然保持唯一性\n",
|
||||
numCPU, float64(total)/duration.Seconds())
|
||||
}
|
||||
}
|
||||
|
||||
// 故意制造时间冲突的恶意测试
|
||||
func TestMaliciousTimeConflict(t *testing.T) {
|
||||
log.Println("开始故意制造时间冲突的恶意测试...")
|
||||
|
||||
// 这个测试试图在完全相同的时间点生成ID
|
||||
const rounds = 100
|
||||
const goroutinesPerRound = 1000
|
||||
|
||||
allResults := make([]int64, 0, rounds*goroutinesPerRound)
|
||||
var globalMutex sync.Mutex
|
||||
|
||||
for round := 0; round < rounds; round++ {
|
||||
log.Printf("第 %d 轮时间冲突测试\n", round+1)
|
||||
|
||||
results := make(chan int64, goroutinesPerRound)
|
||||
var wg sync.WaitGroup
|
||||
var startSignal sync.WaitGroup
|
||||
startSignal.Add(1)
|
||||
|
||||
// 启动goroutine但不让它们开始
|
||||
for i := 0; i < goroutinesPerRound; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
startSignal.Wait()
|
||||
// 在完全相同的时刻调用GenId
|
||||
results <- GenId()
|
||||
}()
|
||||
}
|
||||
|
||||
// 等待一个随机的短时间,然后同时释放所有goroutine
|
||||
time.Sleep(time.Microsecond * time.Duration(rand.Intn(1000)))
|
||||
startSignal.Done()
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
// 收集这一轮的结果
|
||||
roundResults := make([]int64, 0, goroutinesPerRound)
|
||||
for id := range results {
|
||||
roundResults = append(roundResults, id)
|
||||
}
|
||||
|
||||
globalMutex.Lock()
|
||||
allResults = append(allResults, roundResults...)
|
||||
globalMutex.Unlock()
|
||||
|
||||
// 检查这一轮内部是否有重复
|
||||
roundSeen := make(map[int64]bool)
|
||||
roundDuplicates := 0
|
||||
for _, id := range roundResults {
|
||||
if roundSeen[id] {
|
||||
roundDuplicates++
|
||||
t.Errorf("第%d轮发现重复ID: %d", round+1, id)
|
||||
}
|
||||
roundSeen[id] = true
|
||||
}
|
||||
|
||||
if roundDuplicates > 0 {
|
||||
log.Printf("⚠️ 第%d轮发现 %d 个重复ID\n", round+1, roundDuplicates)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查全局重复
|
||||
log.Println("检查全局重复...")
|
||||
globalSeen := make(map[int64]bool)
|
||||
globalDuplicates := 0
|
||||
duplicateIds := make([]int64, 0)
|
||||
|
||||
for _, id := range allResults {
|
||||
if globalSeen[id] {
|
||||
globalDuplicates++
|
||||
duplicateIds = append(duplicateIds, id)
|
||||
t.Errorf("恶意时间冲突测试发现重复ID: %d", id)
|
||||
}
|
||||
globalSeen[id] = true
|
||||
}
|
||||
|
||||
log.Printf("恶意时间冲突测试结果: 总数=%d, 唯一=%d, 重复=%d\n",
|
||||
len(allResults), len(globalSeen), globalDuplicates)
|
||||
|
||||
if len(duplicateIds) > 0 {
|
||||
log.Printf("重复的ID列表: %v\n", duplicateIds[:min(len(duplicateIds), 20)])
|
||||
}
|
||||
|
||||
if globalDuplicates > 0 {
|
||||
t.Fatalf("恶意时间冲突测试发现 %d 个重复ID!这证明了在极端时间冲突下存在问题", globalDuplicates)
|
||||
} else {
|
||||
log.Printf("✅ 即使在故意制造的时间冲突下仍然保持唯一性\n")
|
||||
}
|
||||
}
|
||||
|
||||
// 性能对比测试:int64 vs string 版本
|
||||
func TestPerformanceComparison(t *testing.T) {
|
||||
log.Println("开始性能对比测试: GenId (int64) vs GenSid (string)")
|
||||
|
||||
const iterations = 1000000
|
||||
const goroutines = 1000
|
||||
const idsPerGoroutine = iterations / goroutines
|
||||
|
||||
// 测试 GenId (int64版本)
|
||||
log.Printf("测试 GenId (int64版本): %d 个goroutine,每个生成 %d 个ID\n", goroutines, idsPerGoroutine)
|
||||
start1 := time.Now()
|
||||
|
||||
var wg1 sync.WaitGroup
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg1.Add(1)
|
||||
go func() {
|
||||
defer wg1.Done()
|
||||
for j := 0; j < idsPerGoroutine; j++ {
|
||||
_ = GenId()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg1.Wait()
|
||||
|
||||
duration1 := time.Since(start1)
|
||||
rate1 := float64(iterations) / duration1.Seconds()
|
||||
log.Printf("GenId (int64) 结果: 耗时=%v, 速率=%.2f ID/秒\n", duration1, rate1)
|
||||
|
||||
// 测试 GenSid (string版本)
|
||||
log.Printf("测试 GenSid (string版本): %d 个goroutine,每个生成 %d 个ID\n", goroutines, idsPerGoroutine)
|
||||
start2 := time.Now()
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg2.Add(1)
|
||||
go func() {
|
||||
defer wg2.Done()
|
||||
for j := 0; j < idsPerGoroutine; j++ {
|
||||
_ = GenSid()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg2.Wait()
|
||||
|
||||
duration2 := time.Since(start2)
|
||||
rate2 := float64(iterations) / duration2.Seconds()
|
||||
log.Printf("GenSid (string) 结果: 耗时=%v, 速率=%.2f ID/秒\n", duration2, rate2)
|
||||
|
||||
// 性能对比分析
|
||||
speedupPercent := ((rate2 - rate1) / rate1) * 100
|
||||
log.Printf("\n📊 性能对比分析:\n")
|
||||
log.Printf("GenId (int64): %.2f ID/秒\n", rate1)
|
||||
log.Printf("GenSid (str): %.2f ID/秒\n", rate2)
|
||||
|
||||
if speedupPercent > 0 {
|
||||
log.Printf("✅ GenSid 比 GenId 快 %.2f%%\n", speedupPercent)
|
||||
} else {
|
||||
log.Printf("⚠️ GenSid 比 GenId 慢 %.2f%%\n", -speedupPercent)
|
||||
}
|
||||
|
||||
// 验证两个版本生成的ID格式一致性
|
||||
log.Println("\n🔍 验证ID格式一致性:")
|
||||
for i := 0; i < 5; i++ {
|
||||
intId := GenId()
|
||||
strId := GenSid()
|
||||
log.Printf("GenId: %d (长度: %d), GenSid: %s (长度: %d)\n",
|
||||
intId, len(cast.ToString(intId)), strId, len(strId))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark测试
|
||||
func BenchmarkGenId(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_ = GenId()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkGenSid(b *testing.B) {
|
||||
b.ResetTimer()
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
_ = GenSid()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 长时间性能对比测试 - 延长测试时间获得更准确的性能数据
|
||||
func TestExtendedPerformanceComparison(t *testing.T) {
|
||||
log.Println("开始长时间性能对比测试: GenId (int64) vs GenSid (string)")
|
||||
|
||||
const duration = 10 * time.Second // 延长到10秒
|
||||
const goroutines = 500
|
||||
|
||||
// 测试GenId (int64版本)
|
||||
log.Printf("测试 GenId (int64版本): %d 个goroutine,持续 %v", goroutines, duration)
|
||||
start1 := time.Now()
|
||||
|
||||
results1 := make(chan int64, 100000)
|
||||
var wg1 sync.WaitGroup
|
||||
stop1 := make(chan struct{})
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg1.Add(1)
|
||||
go func() {
|
||||
defer wg1.Done()
|
||||
for {
|
||||
select {
|
||||
case <-stop1:
|
||||
return
|
||||
case results1 <- GenId():
|
||||
// 无延迟,最大化性能测试
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(duration)
|
||||
close(stop1)
|
||||
wg1.Wait()
|
||||
close(results1)
|
||||
|
||||
duration1 := time.Since(start1)
|
||||
count1 := len(results1)
|
||||
rate1 := float64(count1) / duration1.Seconds()
|
||||
|
||||
log.Printf("GenId (int64) 结果: 耗时=%v, 总数=%d, 速率=%.2f ID/秒", duration1, count1, rate1)
|
||||
|
||||
// 测试GenSid (string版本)
|
||||
log.Printf("测试 GenSid (string版本): %d 个goroutine,持续 %v", goroutines, duration)
|
||||
start2 := time.Now()
|
||||
|
||||
results2 := make(chan string, 100000)
|
||||
var wg2 sync.WaitGroup
|
||||
stop2 := make(chan struct{})
|
||||
|
||||
for i := 0; i < goroutines; i++ {
|
||||
wg2.Add(1)
|
||||
go func() {
|
||||
defer wg2.Done()
|
||||
for {
|
||||
select {
|
||||
case <-stop2:
|
||||
return
|
||||
case results2 <- GenSid():
|
||||
// 无延迟,最大化性能测试
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(duration)
|
||||
close(stop2)
|
||||
wg2.Wait()
|
||||
close(results2)
|
||||
|
||||
duration2 := time.Since(start2)
|
||||
count2 := len(results2)
|
||||
rate2 := float64(count2) / duration2.Seconds()
|
||||
|
||||
log.Printf("GenSid (string) 结果: 耗时=%v, 总数=%d, 速率=%.2f ID/秒", duration2, count2, rate2)
|
||||
|
||||
// 性能对比分析
|
||||
log.Println("\n📊 长时间性能对比分析:")
|
||||
log.Printf("GenId (int64): %.2f ID/秒", rate1)
|
||||
log.Printf("GenSid (str): %.2f ID/秒", rate2)
|
||||
|
||||
if rate2 > rate1 {
|
||||
percentage := ((rate2 - rate1) / rate1) * 100
|
||||
log.Printf("✅ GenSid 比 GenId 快 %.2f%%", percentage)
|
||||
} else {
|
||||
percentage := ((rate1 - rate2) / rate2) * 100
|
||||
log.Printf("⚠️ GenId 比 GenSid 快 %.2f%%", percentage)
|
||||
}
|
||||
|
||||
// 验证ID格式一致性
|
||||
log.Println("\n🔍 验证ID格式一致性:")
|
||||
for i := 0; i < 5; i++ {
|
||||
id1 := GenId()
|
||||
id2 := GenSid()
|
||||
log.Printf("GenId: %d (长度: %d), GenSid: %s (长度: %d)",
|
||||
id1, len(cast.ToString(id1)), id2, len(id2))
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助函数
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
Reference in New Issue
Block a user