需求描述
- 支持配置多个奖品及对应权重
- 保证抽奖结果符合权重概率分布
- 防止重复中奖
- 提供抽奖结果验证接口
完整实现代码
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语言 权重抽奖系统内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论