Go语言实现权重抽奖系统的项目实践

作者:

文章目录
  • 支持配置多个奖品及对应权重 保证抽奖结果符合权重概率分布 防止重复中奖 提供抽奖结果验证接口
  • package main import ( “crypto/rand” “encoding/json” “fmt” “math/big” “net/http” “sync” ) // 奖品配置 type Prize struct { ID int `json:”id”` Name string `json:”name”` Weight int `json:”weight”` // 权重值(非百分比) } // 抽奖系统 type LotterySystem struct { prizes []Prize totalWeight int issuedPrizes map[int]bool mu sync.Mutex } // 初始化抽奖系统 func NewLotterySystem(prizes []Prize) *LotterySystem { total := 0 for _, p := range prizes { total += p.Weight } return &LotterySystem{ prizes: prizes, totalWeight: total, issuedPrizes: make(map[int]bool), } } // 安全随机数生成 func secureRandom(max int) (int, error) { n, err := rand.Int(rand.Reader, big.NewInt(int64(max))) if err != nil { return 0, err } return int(n.Int64()), nil } // 执行抽奖 func (ls *LotterySystem) Draw() (*Prize, error) { ls.mu.Lock() defer ls.mu.Unlock() if ls.totalWeight == 0 { return nil, fmt.Errorf(“no available prizes”) } // 生成随机数 randomNum, err := secureRandom(ls.totalWeight) if err != nil { return nil, err } // 权重选择 current := 0 for _, p := range ls.prizes { current += p.Weight if randomNum < current { if ls.issuedPrizes[p.ID] { continue // 已发放的奖品跳过 } ls.issuedPrizes[p.ID] = true return &p, nil } } return nil, fmt.Errorf(“draw failed”) } // HTTP服务 func main() { // 初始化奖品池 prizes := []Prize{ {ID: 1, Name: “一等奖”, Weight: 1}, {ID: 2, Name: “二等奖”, Weight: 5}, {ID: 3, Name: “三等奖”, Weight: 20}, {ID: 4, Name: “参与奖”, Weight: 74}, } lottery := NewLotterySystem(prizes) http.HandleFunc(“/draw”, func(w http.ResponseWriter, r *http.Request) { prize, err := lottery.Draw() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set(“Content-Type”, “application/json”) json.NewEncoder(w).Encode(prize) }) fmt.Println(“抽奖服务已启动,监听端口 8080”) http.ListenAndServe(“:8080”, nil) }
  • 权重算法: // 权重选择逻辑 current := 0 for _, p := range ls.prizes { current += p.Weight if randomNum < current { return &p } } 使用累计权重区间算法 保证概率分布准确性 安全随机数: // 使用crypto/rand生成安全随机数 func secureRandom(max int) (int, error) { n, err := rand.Int(rand.Reader, big.NewInt(int64(max))) // … } 避免使用math/rand的可预测性 满足安全抽奖需求 并发控制: var mu sync.Mutex func (ls *LotterySystem) Draw() { ls.mu.Lock() defer ls.mu.Unlock() // … } 使用互斥锁保证线程安全 防止并发抽奖导致的数据竞争 防重复机制: issuedPrizes map[int]bool 使用内存映射记录已发放奖品 生产环境可替换为Redis等持久化存储
  • 概率可视化验证: // 添加测试端点验证概率分布 http.HandleFunc(“/test”, func(w http.ResponseWriter, r *http.Request) { results := make(map[int]int) for i := 0; i < 10000; i++ { tempLottery := NewLotterySystem(prizes) prize, _ := tempLottery.Draw() results[prize.ID]++ } json.NewEncoder(w).Encode(results) }) 分布式锁扩展: // 使用Redis分布式锁 func (ls *LotterySystem) DistributedDraw() { lock := redis.NewLock(“lottery_lock”) err := lock.Lock() // …抽奖逻辑… lock.Unlock() } 奖品库存管理: type Prize struct { // … Stock int // 新增库存字段 } func (ls *LotterySystem) Draw() { // 检查库存 if p.Stock <= 0 { continue } // 扣减库存 p.Stock– }
  • 启动服务: go run main.go 测试抽奖: curl http://localhost:8080/draw # 示例返回:{“id”:3,”name”:”三等奖”,”weight”:20} 概率验证测试: curl http://localhost:8080/test # 返回万次抽奖结果分布
  • 性能优化: 使用预计算总权重值 内存级锁粒度控制 对象池复用 安全增强: JWT用户身份验证 抽奖频率限制 敏感操作日志 业务扩展: 支持不同抽奖活动 奖品有效期管理 中奖名单公示 到此这篇关于Go语言实现权重抽奖系统的项目实践的文章就介绍到这了,更多相关Go语言 权重抽奖系统内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: GoLang抽奖系统简易实现流程 Django扫码抽奖平台的配置过程详解
  • 目录
    • 需求描述
    • 完整实现代码
    • 核心功能说明
    • 扩展功能建议
    • 运行测试
    • 关键优化点

    • 支持配置多个奖品及对应权重
    • 保证抽奖结果符合权重概率分布
    • 防止重复中奖
    • 提供抽奖结果验证接口

    package main
    
    import (
        "crypto/rand"
        "encoding/json"
        "fmt"
        "math/big"
        "net/http"
        "sync"
    )
    
    // 奖品配置
    type Prize struct {
        ID     int    `json:"id"`
        Name   string `json:"name"`
        Weight int    `json:"weight"` // 权重值(非百分比)
    }
    
    // 抽奖系统
    type LotterySystem struct {
        prizes       []Prize
        totalWeight  int
        issuedPrizes map[int]bool
        mu           sync.Mutex
    }
    
    // 初始化抽奖系统
    func NewLotterySystem(prizes []Prize) *LotterySystem {
        total := 0
        for _, p := range prizes {
            total += p.Weight
        }
        return &LotterySystem{
            prizes:       prizes,
            totalWeight:  total,
            issuedPrizes: make(map[int]bool),
        }
    }
    
    // 安全随机数生成
    func secureRandom(max int) (int, error) {
        n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
        if err != nil {
            return 0, err
        }
        return int(n.Int64()), nil
    }
    
    // 执行抽奖
    func (ls *LotterySystem) Draw() (*Prize, error) {
        ls.mu.Lock()
        defer ls.mu.Unlock()
    
        if ls.totalWeight == 0 {
            return nil, fmt.Errorf("no available prizes")
        }
    
        // 生成随机数
        randomNum, err := secureRandom(ls.totalWeight)
        if err != nil {
            return nil, err
        }
    
        // 权重选择
        current := 0
        for _, p := range ls.prizes {
            current += p.Weight
            if randomNum < current {
                if ls.issuedPrizes[p.ID] {
                    continue // 已发放的奖品跳过
                }
                ls.issuedPrizes[p.ID] = true
                return &p, nil
            }
        }
    
        return nil, fmt.Errorf("draw failed")
    }
    
    // HTTP服务
    func main() {
        // 初始化奖品池
        prizes := []Prize{
            {ID: 1, Name: "一等奖", Weight: 1},
            {ID: 2, Name: "二等奖", Weight: 5},
            {ID: 3, Name: "三等奖", Weight: 20},
            {ID: 4, Name: "参与奖", Weight: 74},
        }
    
        lottery := NewLotterySystem(prizes)
    
        http.HandleFunc("/draw", func(w http.ResponseWriter, r *http.Request) {
            prize, err := lottery.Draw()
            if err != nil {
                http.Error(w, err.Error(), http.StatusInternalServerError)
                return
            }
    
            w.Header().Set("Content-Type", "application/json")
            json.NewEncoder(w).Encode(prize)
        })
    
        fmt.Println("抽奖服务已启动,监听端口 8080")
        http.ListenAndServe(":8080", nil)
    }

    权重算法:

    // 权重选择逻辑
    current := 0
    for _, p := range ls.prizes {
        current += p.Weight
        if randomNum < current {
            return &p
        }
    }
    • 使用累计权重区间算法
    • 保证概率分布准确性

    安全随机数:

    // 使用crypto/rand生成安全随机数
    func secureRandom(max int) (int, error) {
        n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
        // ...
    }
    • 避免使用math/rand的可预测性
    • 满足安全抽奖需求

    并发控制:

    var mu sync.Mutex
    
    func (ls *LotterySystem) Draw() {
        ls.mu.Lock()
        defer ls.mu.Unlock()
        // ...
    }
    • 使用互斥锁保证线程安全
    • 防止并发抽奖导致的数据竞争

    防重复机制:

    issuedPrizes map[int]bool
    • 使用内存映射记录已发放奖品
    • 生产环境可替换为Redis等持久化存储

    概率可视化验证:

    // 添加测试端点验证概率分布
    http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
        results := make(map[int]int)
        for i := 0; i < 10000; i++ {
            tempLottery := NewLotterySystem(prizes)
            prize, _ := tempLottery.Draw()
            results[prize.ID]++
        }
        json.NewEncoder(w).Encode(results)
    })

    分布式锁扩展:

    // 使用Redis分布式锁
    func (ls *LotterySystem) DistributedDraw() {
        lock := redis.NewLock("lottery_lock")
        err := lock.Lock()
        // ...抽奖逻辑...
        lock.Unlock()
    }

    奖品库存管理:

    type Prize struct {
        // ...
        Stock     int // 新增库存字段
    }
    func (ls *LotterySystem) Draw() {
        // 检查库存
        if p.Stock <= 0 {
            continue
        }
        // 扣减库存
        p.Stock--
    }

    启动服务:

    go run main.go

    测试抽奖:

    curl http://localhost:8080/draw
    # 示例返回:{"id":3,"name":"三等奖","weight":20}

    概率验证测试:

    curl http://localhost:8080/test
    # 返回万次抽奖结果分布

    性能优化:

    • 使用预计算总权重值
    • 内存级锁粒度控制
    • 对象池复用

    安全增强:

    • JWT用户身份验证
    • 抽奖频率限制
    • 敏感操作日志

    业务扩展:

    • 支持不同抽奖活动
    • 奖品有效期管理
    • 中奖名单公示

    到此这篇关于Go语言实现权重抽奖系统的项目实践的文章就介绍到这了,更多相关Go语言 权重抽奖系统内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

    您可能感兴趣的文章:

    • GoLang抽奖系统简易实现流程
    • Django扫码抽奖平台的配置过程详解

    站内搜索