Golang|抽獎相關

文章目錄

    • 抽獎核心算法
    • 生成抽獎大轉盤
    • 抽獎接口實現

抽獎核心算法

  • 我們可以根據 單商品庫存量/總商品庫存量 得到每個商品被抽中的概率,可以想象這樣一條 0-1 的數軸,數軸上的每一段相當于一種商品,概率之和為1

在這里插入圖片描述

  • 抽獎時,我們會生成 U(0,1) 上的一個隨機數,這個數位于哪個線段上就對應著抽中了對應的商品。
  • 構建線段,時間復雜度 O(n)
  • 用二分查找算法查找隨機數位于哪一段,時間復雜度 O(logn),采集k個樣本需要再乘以k

  • 接下來介紹二分查找區間算法:
  • N 個點把實數域分割成 N+1 段,target 是隨機生成的實數
  • target 應該落在哪一段上?
  • 定義 array[i-1] < target < array[i] 為落在第 i 條線段上,代表第 i 個獎品被抽中
    在這里插入圖片描述
// BinarySearch 查找 >= target 的最小元素下標,arr單調遞增(不能存在重復元素)
// 如果target比arr的最后一個元素還大,返回最后一個元素下標
func BinarySearch(arr []float64, target float64) int {if len(arr) == 0 {return -1}left := 0right := len(arr)for left < right {// 通用條件if target <= arr[left] {return left}if target > arr[right-1] {return right}// len(arr) == 2, mid在left和right之間, 選擇left的概率值if left == right-1 {return right}// len(arr) >= 3mid := (left + right) / 2if target < arr[mid] {right = mid} else if target == arr[mid] {return mid} else {left = mid // NOTE: 這里不是找直接數值,而是區間}}return -1
}

在這里插入圖片描述

生成抽獎大轉盤

  • 首先看看我們對于抽獎大轉盤所設計的 mysql 數據庫表結構
-- ----------------------------
-- DataBase
-- ----------------------------
CREATE DATABASE lottery;use lottery;-- ----------------------------
-- Table structure for inventory
-- ----------------------------
DROP TABLE IF EXISTS `inventory`;
CREATE TABLE `inventory` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT "獎品id, 自增",`created_at` DATETIME(3) NULL DEFAULT CURRENT_TIMESTAMP COMMENT "創建時間",`updated_at` DATETIME(3) NULL DEFAULT NULL COMMENT "更新時間",`deleted_at` DATETIME(3) NULL DEFAULT NULL COMMENT "刪除時間",`name` varchar(20) NOT NULL COMMENT "獎品名稱",`description` varchar(100) NOT NULL DEFAULT "" COMMENT "獎品描述",`picture` varchar(200) NOT NULL DEFAULT "0" COMMENT "獎品圖片",`price` int(11) NOT NULL DEFAULT "0" COMMENT "價值",`count` int(11) NOT NULL DEFAULT "0" COMMENT "庫存量",PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 COMMENT="獎品庫存表";insert into `inventory` (id,name,picture,price,count) values (1,'謝謝參與','img/face.png',0,0);
insert into `inventory` (name,picture,price,count) values ('籃球','img/ball.jpeg',100,1000),('水杯','img/cup.jpeg',80,1000),('電腦','img/laptop.jpeg',6000,200),('平板','img/pad.jpg',4000,300),('手機','img/phone.jpeg',5000,400),('鍋','img/pot.jpeg',120,1000),('茶葉','img/tea.jpeg',90,1000),('無人機','img/uav.jpeg',400,100),('酒','img/wine.jpeg',160,500);-- ----------------------------
-- Table structure for order
-- ----------------------------
DROP TABLE IF EXISTS `order`;
CREATE TABLE `order` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT "訂單id, 自增",`created_at` DATETIME(3) NULL DEFAULT CURRENT_TIMESTAMP COMMENT "創建時間",`updated_at` DATETIME(3) NULL DEFAULT NULL COMMENT "更新時間",`deleted_at` DATETIME(3) NULL DEFAULT NULL COMMENT "刪除時間",`gift_id` int(11) NOT NULL COMMENT "商品id",`user_id` int(11) NOT NULL COMMENT "用戶id",`count` int(11) NOT NULL DEFAULT "1" COMMENT "購買數量",PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=189549 DEFAULT CHARSET=utf8mb4 COMMENT="訂單表";

在這里插入圖片描述
在這里插入圖片描述

  • 上面這一段,在數據量不大的時候還是可以的,但是數據量一大,在千萬級以上大表的場景下就不行啦,會導致長時間的阻塞,而且讀出來內存也不夠

在這里插入圖片描述

  • V2是對其優化,主要是一個分頁查詢思路,每次把一頁的數據放入一個channel中,然后用一個go協程每次從channel中讀出數據寫入redis
    在這里插入圖片描述

  • 對于每個商品的 count 字段,每次被抽中都應該 count 對應的值減1,但是在高并發的情況下mysql可能扛不住這么大并發量下的頻繁寫入,考慮先記錄在redis里面,真正的減1操作是在redis里面實現的。

  • 在前端頁面初始化的時候我們需要把整個大轉盤的頁面通過后端服務器返回的數據去渲染出整個大轉盤出來,所以需要一開始通過 InitInventory 函數獲得所有獎品的初始庫存,存入redis。

在這里插入圖片描述

  • 看看前端的代碼:
<body><div class="center" id="my-lucky"></div><script>var giftMap = new Map();  //維護獎品ID和轉盤里獎品index的對應關系$(document).ready(function () {$.ajax({type: "GET",url: "api/v1/gifts",success: function (data) {console.log(data)let gifts = data["data"]var prizes=new Array();$.each(gifts,function(index,gift){giftMap[gift.Id]=index;prizes[index]= { background: '#e9e8fe', fonts: [{ text: gift.Name }], imgs:[{src:gift.Picture,top:30,width:80,height:80}] };})// 直接使用luch-canvas抽獎插件  https://100px.net/usage/js.htmlconst myLucky = new LuckyCanvas.LuckyWheel('#my-lucky', {width: '600px',height: '600px',blocks: [{ padding: '10px', background: '#869cfa' }],prizes: prizes,buttons: [{ radius: '40%', background: '#617df2' },{ radius: '35%', background: '#afc8ff' },{radius: '30%', background: '#869cfa',pointer: true,fonts: [{ text: '抽獎', top: '-10px' }]},],start: function() {$.ajax({type: "GET",url: "api/v1/lucky",success: function (giftId) {if(giftId=="0"){alert("抽獎結束")}else{myLucky.play();idx=giftMap[giftId];myLucky.stop(idx);}}}).fail(function (result, result1, result2) {alert("出錯了");});},end: function(prize) { // 游戲停止時觸發alert('恭喜中獎: ' + prize.fonts[0].text)}})}}).fail(function (result, result1, result2) {$('#my-lucky').html("數據加載失敗");});});</script>
</body>
  • 我們可以看到前端的代碼邏輯是先放一個空的div,然后頁面加載好之后通過js代碼發起一個請求去請求"/gifts"這個接口獲得數據渲染生成大轉盤。
  • 這里有個小細節,我們后端返回給前端gifts數據的時候要記得抹掉敏感信息,也就是說我們的抽獎概率是通過商品的庫存量來決定的,我們不希望前端拿到json字符串后看到庫存量,所以我們的gifts返回給前端的時候記得把所有的庫存量都置為0。

在這里插入圖片描述

type Inventory struct {ID 			uint 	`gorm:"column:id"`Name 		string 	`gorm:"column:name"`Description string  `gorm:"column:description"`Picture 	string 	`gorm:"column:picture"`Price 		int 	`gorm:"column:price"`Count 		int		`gorm:"column:count"`
}

在這里插入圖片描述

  • 上面這段代碼就是從redis上獲取所有獎品的庫存量,其中商品id作為key的時候會統一加一個前綴prefix

抽獎接口實現

在這里插入圖片描述

  • 當我們按下抽獎這個按鈕后,前端會用js代碼請求"/lucky"接口,由后端返回本次抽獎抽中了哪個商品id

在這里插入圖片描述
在這里插入圖片描述

  • ids和probs兩個是一一對應的,一個存的是獎品id一個存的是獎品的庫存量
  • 如果獎品已經count為0了,說明已經抽沒了,不應該再參與抽獎
  • 為什么要給前端傳一個0,因為這個0有特殊的意思,前端收到0后會告訴用戶抽獎已經結束
  • 有可能同時對一個庫存量為1的商品去執行減1操作,會導致庫存量為負數,這個時候我們會執行新一輪的抽獎,重新再抽一遍,如果執行指定次數后還是失敗,則會返回最后一行代碼,謝謝參與

在這里插入圖片描述

  • redis Decr 是支持原子性支持并發的

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901860.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901860.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901860.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OpenCV 圖形API(43)顏色空間轉換-----將 BGR 圖像轉換為 LUV 色彩空間函數BGR2LUV()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 將圖像從BGR色彩空間轉換為LUV色彩空間。 該函數將輸入圖像從BGR色彩空間轉換為LUV。B、G和R通道值的傳統范圍是0到255。 輸出圖像必須是8位無符…

【Python】用Python寫一個俄羅斯方塊玩玩

【Python】用Python寫一個俄羅斯方塊玩玩 一、引言1.成品效果展示 二、思考準備1.思考設計2.代碼設計2.1 游戲頁面2.2 控件設計2.2.1 方塊生成2.2.2 方塊碰撞2.2.3 方塊消融2.2.4 游戲主循環2.2.5 游戲窗口 三、游戲完整版 一、引言 今日看到侄子在玩游戲&#xff0c;湊近一看…

維港首秀!沃飛長空AE200亮相香港特別行政區

4月13日-16日&#xff0c;第三屆香港國際創科展在香港會議展覽中心盛大舉辦。 作為國內領先、國際一流的eVTOL主機廠&#xff0c;沃飛長空攜旗下AE200批產構型登陸國際舞臺&#xff0c;以前瞻性的創新技術與商業化應用潛力&#xff0c;吸引了來自全球17個國家及地區的行業領袖…

Openfein實現遠程調用的方法(實操)

文章目錄 環境準備一、URL中接收參數二、接收一個參數三、接收多個參數四、傳遞對象五、傳遞JSON格式數據 環境準備 下面的配置&#xff0c;服務調用方加入即可。 依賴導入&#xff1a; <!-- openfeign依賴--><dependency><groupId>org.springframe…

Bright+Data網頁解鎖器:旅游行業數據革命的“隱形引擎”

在數字經濟浪潮中&#xff0c;旅游行業正經歷前所未有的變革。當消費者指尖滑動間完成跨國酒店預訂&#xff0c;當航空公司每秒調整萬次艙位價格&#xff0c;背后是一場無聲的數據戰爭。而在這場戰爭中&#xff0c;BrightData網頁解鎖器正成為旅游企業破局的關鍵武器——它像一…

OpenCV 圖形API(38)圖像濾波-----Sobel 算子操作函數Sobel()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 cv::gapi::Sobel 函數是 OpenCV 的 G-API 模塊中用于執行 Sobel 算子操作的一個函數&#xff0c;主要用于圖像的邊緣檢測。Sobel 算子通過計算圖…

CS5346 - Interactivity in Visualization 可視化中的交互

文章目錄 Visualization representation interactionInteraction &#xff08;交互&#xff09;Benefits (好處)Typical Interaction Techniques&#xff08;交互技術&#xff09;SelectFilteringAbstract / Elaborate幾何放縮&#xff08;Geometric zoom)語義放縮&#xff0…

第十六屆藍橋杯大賽軟件賽省賽 C++ 大學 B 組 部分題解

賽時參加的是Python組&#xff0c;這是賽后寫的題解&#xff0c;還有兩題暫時還不會&#xff0c;待更新 題目鏈接題目列表 - 洛谷 | 計算機科學教育新生態 A 移動距離 答案&#xff1a;1576 C 可分解的正整數 Python3 import itertools from functools import cmp_to_ke…

Vue 解決 Error: please transfer a valid prop path to form item!

在 Vue.js 中使用表單驗證庫&#xff08;如 VeeValidate 或 Element UI 的表單組件時&#xff09;&#xff0c;遇到錯誤信息 "please transfer a valid prop path to form item!" 通常指的是在表單項的屬性綁定中&#xff0c;路徑&#xff08;prop path&#xff09;不…

在 Visual Studio Code 中安裝通義靈碼 - 智能編碼助手

高效的編碼工具對于提升開發效率和代碼質量至關重要。 通義靈碼作為一款智能編碼助手&#xff0c;為開發者提供了全方位的支持。 本文將詳細介紹如何在 Visual Studio Code&#xff08;簡稱 VSCode&#xff09;中安裝通義靈碼&#xff0c;以及如何進行相關配置以開啟智能編碼…

SQL 解析 with as dual sysdate level

目錄 sql的運行順序 with as EXTRACT ?編輯 dual sysdate level ?編輯 ?編輯 Oracle中的日期存儲 核心部分 拆解字符串并計算最小值 關聯子查詢 NVL 函數 REGEXP_SUBSTR() sql的運行順序 <select id="getTrendList" parameterType="java.uti…

快手OneRec 重構推薦系統:從檢索排序到生成統一的躍遷

文章目錄 1. 背景2. 方法2.1 OneRec框架2.2 Preliminary2.3 生成會話列表2.4 利用獎勵模型進行迭代偏好對齊2.4.1 訓練獎勵模型2.4.2 迭代偏好對齊 3. 總結 昨天面試的時候聊到了OneRec&#xff0c;但是由于上次看這篇文章已經是一個月之前&#xff0c;忘得差不多了&#xff0c…

軟考高級系統架構設計師-第11章 系統架構設計

【本章學習建議】 根據考試大綱&#xff0c;本章不僅考查系統架構設計師單選題&#xff0c;預計考12分左右&#xff0c;而且案例分析和論文寫作也是必考&#xff0c;對應第二版教材第7章&#xff0c;屬于重點學習的章節。 軟考高級系統架構設計師VIP課程https://edu.csdn.net/…

selenium之文件下載

Selenium 自動化測試&#xff1a;輕松搞定文件下載 在 Web 自動化測試中&#xff0c;經常會遇到需要驗證文件下載功能的場景。例如&#xff0c;測試報告的導出、用戶上傳文件的下載、PDF 文檔的生成與下載等等。Selenium 本身并沒有直接處理文件下載的內置方法&#xff0c;但我…

基于遷移學習實現肺炎X光片診斷分類

大家好&#xff0c;我是帶我去滑雪&#xff01; 肺炎是全球范圍內致死率較高的疾病之一&#xff0c;尤其是在老年人、免疫系統較弱的患者群體中&#xff0c;更容易引發嚴重并發癥。傳統上&#xff0c;肺炎的診斷依賴于醫生的臨床經驗以及影像學檢查&#xff0c;尤其是X光片&…

工業數據治理范式革新:時序數據庫 TDengine虛擬表技術解析

小T導讀&#xff1a;在工業數字化過程中&#xff0c;數據如何從設備采集順利“爬坡”到上層應用&#xff0c;一直是個難題。傳統“單列模型”雖貼合設備協議&#xff0c;卻讓上層分析舉步維艱。TDengine 用一種更聰明的方法打通了這條數據通路&#xff1a;不強求建模、不手動轉…

Redis面試——日志

一、RDB&#xff08;Redis DataBase&#xff09; RDB 全程是 Redis DataBase&#xff0c;它是一種將 Redis 在某一時刻內存中的數據以快照形式保存到磁盤的機制 &#xff0c;相當于給執行save/bgsave命令時刻的內存數據庫數據拍了一張快照我們如果通過save命令來執行快照&…

【Android】常用參數實踐 用戶界面UI 布局文件XML

本文將系統總結 Android XML 布局的通用參數和常用布局類型的專屬規則 一、通用布局參數 這些參數適用于所有 View 和 ViewGroup&#xff0c;是布局設計的基石。 1. 尺寸控制 android:layout_width 與 android:layout_height 定義視圖的寬度和高度&#xff0c;可選值&#xf…

解決 VSCode 中 NVM 配置后無法識別 Node 和 NPM 的問題

在開發中&#xff0c;我們經常需要使用 Node.js 和 NPM 來管理 JavaScript 項目依賴&#xff0c;而 NVM&#xff08;Node Version Manager&#xff09;是開發者在本地環境中管理多個 Node.js 版本的得力工具。不過&#xff0c;有時候在 VSCode 中配置完 NVM 后&#xff0c;可能…

BGP分解實驗·23——BGP選路原則之路由器標識

在選路原則需要用到Router-ID做選路決策時&#xff0c;其對等體Router-ID較小的路由將被優選&#xff1b;其中&#xff0c;當路由被反射時&#xff0c;包含起源器ID屬性時&#xff0c;該屬性將代替router-id做比較。 實驗拓撲如下&#xff1a; 實驗通過調整路由器R1和R2的rout…