Go語言實現權重抽獎系統的項目實踐
更新時間:2025年04月17日 11:06:49 作者:程序智享家
本文主要介紹了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 } // 執(zhí)行抽獎 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 // 已發(fā)放的獎品跳過 } 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("抽獎服務已啟動,監(jiān)聽端口 8080") http.ListenAndServe(":8080", nil) }
核心功能說明
權重算法:
// 權重選擇邏輯 current := 0 for _, p := range ls.prizes { current += p.Weight if randomNum < current { return &p } }
- 使用累計權重區(qū)間算法
- 保證概率分布準確性
安全隨機數:
// 使用crypto/rand生成安全隨機數 func secureRandom(max int) (int, error) { n, err := rand.Int(rand.Reader, big.NewInt(int64(max))) // ... }
- 避免使用math/rand的可預測性
- 滿足安全抽獎需求
并發(fā)控制:
var mu sync.Mutex func (ls *LotterySystem) Draw() { ls.mu.Lock() defer ls.mu.Unlock() // ... }
- 使用互斥鎖保證線程安全
- 防止并發(fā)抽獎導致的數據競爭
防重復機制:
issuedPrizes map[int]bool
- 使用內存映射記錄已發(fā)放獎品
- 生產環(huán)境可替換為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 # 返回萬次抽獎結果分布
關鍵優(yōu)化點
性能優(yōu)化:
- 使用預計算總權重值
- 內存級鎖粒度控制
- 對象池復用
安全增強:
- JWT用戶身份驗證
- 抽獎頻率限制
- 敏感操作日志
業(yè)務擴展:
- 支持不同抽獎活動
- 獎品有效期管理
- 中獎名單公示
到此這篇關于Go語言實現權重抽獎系統的項目實踐的文章就介紹到這了,更多相關Go語言 權重抽獎系統內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:
相關文章
Golang使用gin模板渲染base64圖片出現#ZgotmplZ的解決辦法
這篇文章主要介紹了Golang使用gin模板渲染base64圖片出現#ZgotmplZ的的場景復現和解決辦法,文中通過代碼示例講解的非常詳細,對大家解決問題有一定的幫助,需要的朋友可以參考下2024-05-05