当前位置: 代码网 > it编程>前端脚本>Golang > Go语言实现权重抽奖系统的项目实践

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

2025年04月24日 Golang 我要评论
需求描述支持配置多个奖品及对应权重保证抽奖结果符合权重概率分布防止重复中奖提供抽奖结果验证接口完整实现代码package mainimport ( "crypto/rand" "encod

需求描述

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

完整实现代码

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语言 权重抽奖系统内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com