panghu 8 сар өмнө
parent
commit
a46df2840b
4 өөрчлөгдсөн 166 нэмэгдсэн , 11 устгасан
  1. 1 1
      api/base.go
  2. 8 2
      api/ceshi.go
  3. 156 7
      pkg/order/order.go
  4. 1 1
      router/api_ceshi.go

+ 1 - 1
api/base.go

@@ -18,7 +18,7 @@ type pageData struct {
 // ResponseSuccess 成功响应格式
 func (b BaseController) responseSuccess(c *gin.Context, data interface{}) {
 	c.JSON(http.StatusOK, gin.H{
-		"code":    0,
+		"code":    200,
 		"message": "success",
 		"data":    data,
 	})

+ 8 - 2
api/ceshi.go

@@ -9,6 +9,12 @@ type CeshiController struct {
 	BaseController
 }
 
-func (cs CeshiController) GetTime(c *gin.Context) {
-	order.TestConcurrentGeneration()
+func (cs CeshiController) GetOrderSn(c *gin.Context) {
+	//order.TestConcurrentGenerationV3()
+	//order.StressTest()
+
+	generator := order.NewOrderNoGenerator(1)
+	//str := generator.Generate()
+	str := generator.GenerateString("382FS")
+	cs.responseSuccess(c, str)
 }

+ 156 - 7
pkg/order/order.go

@@ -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()
+			}
+		}
+	}
+}

+ 1 - 1
router/api_ceshi.go

@@ -11,7 +11,7 @@ func init() {
 		// 用户路由组
 		ceshiGroup := v1.Group("/ceshi")
 		{
-			ceshiGroup.GET("/inviteCode", api.CeshiController{}.GetTime)
+			ceshiGroup.GET("/ordersn", api.CeshiController{}.GetOrderSn)
 		}
 	})
 }