• 设为首页
  • 收藏本站
  • 积分充值
  • VIP赞助
  • 手机版
  • 微博
  • 微信
    微信公众号 添加方式:
    1:搜索微信号(888888
    2:扫描左侧二维码
  • 快捷导航
    福建二哥 门户 查看主题

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

    发布者: 琛瑞6678 | 发布时间: 2025-8-14 14:06| 查看数: 11| 评论数: 0|帖子模式

    需求描述


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

    完整实现代码
    1. package main

    2. import (
    3.     "crypto/rand"
    4.     "encoding/json"
    5.     "fmt"
    6.     "math/big"
    7.     "net/http"
    8.     "sync"
    9. )

    10. // 奖品配置
    11. type Prize struct {
    12.     ID     int    `json:"id"`
    13.     Name   string `json:"name"`
    14.     Weight int    `json:"weight"` // 权重值(非百分比)
    15. }

    16. // 抽奖系统
    17. type LotterySystem struct {
    18.     prizes       []Prize
    19.     totalWeight  int
    20.     issuedPrizes map[int]bool
    21.     mu           sync.Mutex
    22. }

    23. // 初始化抽奖系统
    24. func NewLotterySystem(prizes []Prize) *LotterySystem {
    25.     total := 0
    26.     for _, p := range prizes {
    27.         total += p.Weight
    28.     }
    29.     return &LotterySystem{
    30.         prizes:       prizes,
    31.         totalWeight:  total,
    32.         issuedPrizes: make(map[int]bool),
    33.     }
    34. }

    35. // 安全随机数生成
    36. func secureRandom(max int) (int, error) {
    37.     n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
    38.     if err != nil {
    39.         return 0, err
    40.     }
    41.     return int(n.Int64()), nil
    42. }

    43. // 执行抽奖
    44. func (ls *LotterySystem) Draw() (*Prize, error) {
    45.     ls.mu.Lock()
    46.     defer ls.mu.Unlock()

    47.     if ls.totalWeight == 0 {
    48.         return nil, fmt.Errorf("no available prizes")
    49.     }

    50.     // 生成随机数
    51.     randomNum, err := secureRandom(ls.totalWeight)
    52.     if err != nil {
    53.         return nil, err
    54.     }

    55.     // 权重选择
    56.     current := 0
    57.     for _, p := range ls.prizes {
    58.         current += p.Weight
    59.         if randomNum < current {
    60.             if ls.issuedPrizes[p.ID] {
    61.                 continue // 已发放的奖品跳过
    62.             }
    63.             ls.issuedPrizes[p.ID] = true
    64.             return &p, nil
    65.         }
    66.     }

    67.     return nil, fmt.Errorf("draw failed")
    68. }

    69. // HTTP服务
    70. func main() {
    71.     // 初始化奖品池
    72.     prizes := []Prize{
    73.         {ID: 1, Name: "一等奖", Weight: 1},
    74.         {ID: 2, Name: "二等奖", Weight: 5},
    75.         {ID: 3, Name: "三等奖", Weight: 20},
    76.         {ID: 4, Name: "参与奖", Weight: 74},
    77.     }

    78.     lottery := NewLotterySystem(prizes)

    79.     http.HandleFunc("/draw", func(w http.ResponseWriter, r *http.Request) {
    80.         prize, err := lottery.Draw()
    81.         if err != nil {
    82.             http.Error(w, err.Error(), http.StatusInternalServerError)
    83.             return
    84.         }

    85.         w.Header().Set("Content-Type", "application/json")
    86.         json.NewEncoder(w).Encode(prize)
    87.     })

    88.     fmt.Println("抽奖服务已启动,监听端口 8080")
    89.     http.ListenAndServe(":8080", nil)
    90. }
    复制代码
    核心功能说明

    权重算法:
    1. // 权重选择逻辑
    2. current := 0
    3. for _, p := range ls.prizes {
    4.     current += p.Weight
    5.     if randomNum < current {
    6.         return &p
    7.     }
    8. }
    复制代码

    • 使用累计权重区间算法
    • 保证概率分布准确性
    安全随机数:
    1. // 使用crypto/rand生成安全随机数
    2. func secureRandom(max int) (int, error) {
    3.     n, err := rand.Int(rand.Reader, big.NewInt(int64(max)))
    4.     // ...
    5. }
    复制代码

    • 避免使用math/rand的可预测性
    • 满足安全抽奖需求
    并发控制:
    1. var mu sync.Mutex

    2. func (ls *LotterySystem) Draw() {
    3.     ls.mu.Lock()
    4.     defer ls.mu.Unlock()
    5.     // ...
    6. }
    复制代码

    • 使用互斥锁保证线程安全
    • 防止并发抽奖导致的数据竞争
    防重复机制:
    1. issuedPrizes map[int]bool
    复制代码

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

    扩展功能建议

    概率可视化验证:
    1. // 添加测试端点验证概率分布
    2. http.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
    3.     results := make(map[int]int)
    4.     for i := 0; i < 10000; i++ {
    5.         tempLottery := NewLotterySystem(prizes)
    6.         prize, _ := tempLottery.Draw()
    7.         results[prize.ID]++
    8.     }
    9.     json.NewEncoder(w).Encode(results)
    10. })
    复制代码
    分布式锁扩展:
    1. // 使用Redis分布式锁
    2. func (ls *LotterySystem) DistributedDraw() {
    3.     lock := redis.NewLock("lottery_lock")
    4.     err := lock.Lock()
    5.     // ...抽奖逻辑...
    6.     lock.Unlock()
    7. }
    复制代码
    奖品库存管理:
    1. type Prize struct {
    2.     // ...
    3.     Stock     int // 新增库存字段
    4. }
    5. func (ls *LotterySystem) Draw() {
    6.     // 检查库存
    7.     if p.Stock <= 0 {
    8.         continue
    9.     }
    10.     // 扣减库存
    11.     p.Stock--
    12. }
    复制代码
    运行测试

    启动服务:
    1. go run main.go
    复制代码
    测试抽奖:
    1. curl http://localhost:8080/draw
    2. # 示例返回:{"id":3,"name":"三等奖","weight":20}
    复制代码
    概率验证测试:
    1. curl http://localhost:8080/test
    2. # 返回万次抽奖结果分布
    复制代码
    关键优化点

    性能优化:

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

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

    • 支持不同抽奖活动
    • 奖品有效期管理
    • 中奖名单公示
    到此这篇关于Go语言实现权重抽奖系统的项目实践的文章就介绍到这了,更多相关Go语言 权重抽奖系统内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    来源:互联网
    免责声明:如果侵犯了您的权益,请联系站长(1277306191@qq.com),我们会及时删除侵权内容,谢谢合作!

    最新评论

    QQ Archiver 手机版 小黑屋 福建二哥 ( 闽ICP备2022004717号|闽公网安备35052402000345号 )

    Powered by Discuz! X3.5 © 2001-2023

    快速回复 返回顶部 返回列表