|
|
@@ -3,6 +3,7 @@ package order
|
|
|
import (
|
|
|
"fmt"
|
|
|
"sync"
|
|
|
+ "sync/atomic"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
@@ -14,7 +15,7 @@ type Generator struct {
|
|
|
mu sync.Mutex
|
|
|
}
|
|
|
|
|
|
-func NewOrderGenerator(machineID int) *Generator {
|
|
|
+func NewOrderNoGenerator(machineID int) *Generator {
|
|
|
return &Generator{
|
|
|
machineID: machineID,
|
|
|
lastTime: time.Now().UnixMilli(),
|
|
|
@@ -26,26 +27,96 @@ func (g *Generator) Generate() string {
|
|
|
g.mu.Lock()
|
|
|
defer g.mu.Unlock()
|
|
|
|
|
|
- // 获取当前毫秒时间戳
|
|
|
currentTime := time.Now().UnixMilli()
|
|
|
|
|
|
if currentTime == g.lastTime {
|
|
|
g.sequence++
|
|
|
} else {
|
|
|
- g.sequence = 0
|
|
|
+ g.sequence = 1
|
|
|
g.lastTime = currentTime
|
|
|
}
|
|
|
|
|
|
- // 获取当前日期(年月日)
|
|
|
- dateStr := time.Now().Format("20060102")
|
|
|
+ // 格式化时间,包含毫秒
|
|
|
+ t := time.UnixMilli(currentTime)
|
|
|
+ // 格式:年月日时分秒 + 毫秒(3位) + 机器ID + 序列号
|
|
|
+ return fmt.Sprintf("%s%03d%02d%04d",
|
|
|
+ t.Format("20060102150405"), // 14位
|
|
|
+ t.Nanosecond()/1e6, // 3位毫秒
|
|
|
+ g.machineID, // 2位
|
|
|
+ g.sequence, // 4位
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+// GenerateString 生成字符串格式订单号
|
|
|
+func (g *Generator) GenerateString(prefix string) string {
|
|
|
+ // 调用无锁Generate获取ID
|
|
|
+ id := g.Generate()
|
|
|
+
|
|
|
+ // 格式化为字符串
|
|
|
+ return fmt.Sprintf("%s%s", prefix, id)
|
|
|
+}
|
|
|
+
|
|
|
+type GeneratorV3 struct {
|
|
|
+ machineID int
|
|
|
+ // 使用一个64位整数存储时间戳(42位)和序列号(22位)
|
|
|
+ // 这样可以原子操作,不需要锁
|
|
|
+ counter uint64
|
|
|
+}
|
|
|
+
|
|
|
+func NewOrderNoGeneratorV3(machineID int) *GeneratorV3 {
|
|
|
+ return &GeneratorV3{
|
|
|
+ machineID: machineID,
|
|
|
+ counter: 0,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (g *GeneratorV3) Generate() string {
|
|
|
+ // 获取当前毫秒时间戳
|
|
|
+ now := uint64(time.Now().UnixMilli())
|
|
|
+
|
|
|
+ // 原子操作获取下一个ID
|
|
|
+ var lastTime, seq uint64
|
|
|
+ for {
|
|
|
+ old := atomic.LoadUint64(&g.counter)
|
|
|
+ lastTime = old >> 22 // 高42位是时间戳
|
|
|
+ seq = old & 0x3FFFFF // 低22位是序列号
|
|
|
|
|
|
- return fmt.Sprintf("%s%02d%04d", dateStr, g.machineID, g.sequence)
|
|
|
+ if now > lastTime {
|
|
|
+ // 时间戳变化,重置序列号
|
|
|
+ seq = 0
|
|
|
+ lastTime = now
|
|
|
+ } else if seq >= 0x3FFFFF { // 序列号达到最大值
|
|
|
+ // 等待下一毫秒
|
|
|
+ for now <= lastTime {
|
|
|
+ time.Sleep(100 * time.Microsecond)
|
|
|
+ now = uint64(time.Now().UnixMilli())
|
|
|
+ }
|
|
|
+ seq = 0
|
|
|
+ lastTime = now
|
|
|
+ } else {
|
|
|
+ seq++
|
|
|
+ }
|
|
|
+
|
|
|
+ newVal := (lastTime << 22) | (seq & 0x3FFFFF)
|
|
|
+ if atomic.CompareAndSwapUint64(&g.counter, old, newVal) {
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化输出
|
|
|
+ t := time.UnixMilli(int64(lastTime))
|
|
|
+ return fmt.Sprintf("%s%03d%02d%06d",
|
|
|
+ t.Format("20060102150405"),
|
|
|
+ t.Nanosecond()/1e6,
|
|
|
+ g.machineID,
|
|
|
+ seq,
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
// 并发测试函数
|
|
|
func TestConcurrentGeneration() {
|
|
|
fmt.Println("=== 并发测试 ===")
|
|
|
- generator := NewOrderGenerator(1)
|
|
|
+ generator := NewOrderNoGenerator(1)
|
|
|
|
|
|
// 使用map检查重复
|
|
|
results := sync.Map{}
|
|
|
@@ -79,3 +150,81 @@ func TestConcurrentGeneration() {
|
|
|
fmt.Printf("生成 %d 个订单号,耗时 %v\n", count, elapsed)
|
|
|
fmt.Printf("平均每秒生成: %.0f 个\n", float64(count)/elapsed.Seconds())
|
|
|
}
|
|
|
+
|
|
|
+// 测试V3版本的并发
|
|
|
+func TestConcurrentGenerationV3() {
|
|
|
+ fmt.Println("\n=== 测试V3版本并发 ===")
|
|
|
+ generator := NewOrderNoGeneratorV3(1)
|
|
|
+
|
|
|
+ results := sync.Map{}
|
|
|
+ var wg sync.WaitGroup
|
|
|
+ start := time.Now()
|
|
|
+
|
|
|
+ // 启动10000个协程同时生成订单号
|
|
|
+ for i := 0; i < 10000; i++ {
|
|
|
+ wg.Add(1)
|
|
|
+ go func(id int) {
|
|
|
+ defer wg.Done()
|
|
|
+ orderNo := generator.Generate()
|
|
|
+
|
|
|
+ // 检查是否重复
|
|
|
+ if _, loaded := results.LoadOrStore(orderNo, true); loaded {
|
|
|
+ fmt.Printf("⚠️ V3 - 发现重复订单号: %s\n", orderNo)
|
|
|
+ }
|
|
|
+ }(i)
|
|
|
+ }
|
|
|
+
|
|
|
+ wg.Wait()
|
|
|
+ elapsed := time.Since(start)
|
|
|
+
|
|
|
+ // 统计结果
|
|
|
+ count := 0
|
|
|
+ results.Range(func(key, value interface{}) bool {
|
|
|
+ count++
|
|
|
+ return true
|
|
|
+ })
|
|
|
+
|
|
|
+ fmt.Printf("V3 - 生成 %d 个订单号,耗时 %v\n", count, elapsed)
|
|
|
+ fmt.Printf("V3 - 平均每秒生成: %.0f 个\n", float64(count)/elapsed.Seconds())
|
|
|
+}
|
|
|
+
|
|
|
+// 压力测试:持续生成订单号
|
|
|
+func StressTest() {
|
|
|
+ fmt.Println("\n=== 压力测试 ===")
|
|
|
+ generator := NewOrderNoGeneratorV3(1)
|
|
|
+
|
|
|
+ results := sync.Map{}
|
|
|
+ duplicateCount := 0
|
|
|
+ var duplicateMutex sync.Mutex
|
|
|
+
|
|
|
+ // 持续生成5秒
|
|
|
+ stop := time.After(5 * time.Second)
|
|
|
+ start := time.Now()
|
|
|
+
|
|
|
+ for i := 0; ; i++ {
|
|
|
+ select {
|
|
|
+ case <-stop:
|
|
|
+ elapsed := time.Since(start)
|
|
|
+ totalCount := 0
|
|
|
+ results.Range(func(key, value interface{}) bool {
|
|
|
+ totalCount++
|
|
|
+ return true
|
|
|
+ })
|
|
|
+
|
|
|
+ fmt.Printf("压力测试 - 总生成: %d 个订单号\n", i)
|
|
|
+ fmt.Printf("压力测试 - 唯一订单号: %d 个\n", totalCount)
|
|
|
+ fmt.Printf("压力测试 - 重复数: %d 个\n", duplicateCount)
|
|
|
+ fmt.Printf("压力测试 - 耗时: %v\n", elapsed)
|
|
|
+ fmt.Printf("压力测试 - QPS: %.0f\n", float64(i)/elapsed.Seconds())
|
|
|
+ return
|
|
|
+
|
|
|
+ default:
|
|
|
+ orderNo := generator.Generate()
|
|
|
+ if _, loaded := results.LoadOrStore(orderNo, true); loaded {
|
|
|
+ duplicateMutex.Lock()
|
|
|
+ duplicateCount++
|
|
|
+ duplicateMutex.Unlock()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|