需求描述
- 支持配置多个奖品及对应权重
- 保证抽奖结果符合权重概率分布
- 防止重复中奖
- 提供抽奖结果验证接口
完整实现代码
- 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--
- }
复制代码 运行测试
启动服务:测试抽奖:- curl http://localhost:8080/draw
- # 示例返回:{"id":3,"name":"三等奖","weight":20}
复制代码 概率验证测试:- curl http://localhost:8080/test
- # 返回万次抽奖结果分布
复制代码 关键优化点
性能优化:
安全增强:
业务扩展:
到此这篇关于Go语言实现权重抽奖系统的项目实践的文章就介绍到这了,更多相关Go语言 权重抽奖系统内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
来源:互联网
免责声明:如果侵犯了您的权益,请联系站长(1277306191@qq.com),我们会及时删除侵权内容,谢谢合作! |
|