Go - 高并发抢到红包实现
// utils.go
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
// 抢红包任务结构体
type task struct {
id uint32 // 表示红包id
callback chan uint // 表示返回的金额
}
const TaskNums = 5 // 并发任务数
func main() {
id, money, num := 88, 100, 10
// 发红包 红包ID 金额 数量
SetRedPack(id, money, num)
// 构造抢红包任务通道
for i := 0; i < TaskNums; i++ {
TasksChan[i] = make(chan task)
}
// 开启goroutine监听任务通道
go GetPackageMoney(TasksChan)
var wg sync.WaitGroup
// 抢红包
for i := 0; i < num+5; i++ {
wg.Add(1)
go GetRedPack(id, &wg)
}
wg.Wait()
}
var (
// 记录红包已抢总金额
sum uint = 0
TasksChan = make([]chan task, TaskNums) // 任务通道
random_seed = rand.New(rand.NewSource(time.Now().UnixNano())) // 分配的随机数
// 使用并发安全字典表示红包集
// key: uint32 为红包id
// value: []uint 为红包内随机金额的列表
packageList = new(sync.Map)
mu sync.Mutex
)
// 发红包方法
func SetRedPack(id, money, num int) {
left_money, left_num := money, num
money_list := make([]uint, num)
for left_money > 0 {
if left_num == 1 {
money_list[num-1] = uint(left_money)
break
}
if left_num == left_money {
for i := 0; i < left_num; i++ {
money_list[i] = 1
}
break
}
rMoney := int(2 * float64(left_money) / float64(left_num))
// 保证分配金额>=1
rand_m := random_seed.Intn(rMoney) + 1
money_list[num-left_num] = uint(rand_m)
left_money -= rand_m
left_num--
}
packageList.Store(uint32(id), money_list)
}
// 监听任务通道方法
func GetPackageMoney(taskschan []chan task) {
for {
select {
case t := <-taskschan[0]:
GetMoney(t)
case t := <-taskschan[1]:
GetMoney(t)
case t := <-taskschan[2]:
GetMoney(t)
case t := <-taskschan[3]:
GetMoney(t)
case t := <-taskschan[4]:
GetMoney(t)
default:
continue
}
}
}
func GetMoney(t task) {
id := t.id
l_money_list, ok := packageList.Load(id)
if ok && l_money_list != nil {
list := l_money_list.([]uint)
r_index := random_seed.Intn(len(list))
money := list[r_index]
// 更新红包金额列表信息
if len(list) > 1 {
if r_index == 0 {
packageList.Store(id, list[1:])
} else if r_index == len(list)-1 {
packageList.Store(id, list[:1])
} else {
packageList.Store(id,
append(list[:r_index], list[r_index+1:]...))
}
} else {
packageList.Delete(id)
}
t.callback <- money
} else {
t.callback <- 0
}
}
func GetRedPack(id int, wg *sync.WaitGroup) {
defer wg.Done()
// 并发安全字典取 value
list1, ok := packageList.Load(uint32(id))
list := list1.([]uint)
// 没取到就代表红包不存在
if !ok || len(list) < 1 {
fmt.Printf("红包不存在,id=%d\n", id)
}
// 构造抢红包任务
callback := make(chan uint)
t := task{
id: uint32(id),
callback: callback,
}
TasksChan[sum%TaskNums] <- t
money := <-t.callback
if money <= 0 {
fmt.Printf("很遗憾,你没有抢到红包\n")
} else {
fmt.Printf("恭喜你抢到一个红包,金额为:%d\n", money)
mu.Lock()
defer mu.Unlock()
sum += money
}
}
Go - 高并发抢到红包实现的更多相关文章
- PHP 高并发、抢票、秒杀 解决方案
对于抢票.秒杀这种业务,我说说自己对这种高并发的理解吧,这里提出个人认为比较可行的几个方案:方案一:使用队列来实现可以基于例如MemcacheQ等这样的消息队列,具体的实现方案这么表述吧比如有100张 ...
- asp.net c# 通过消息队列处理高并发请求(以抢小米手机为例)
网站面对高并发的情况下,除了增加硬件, 优化程序提高以响应速度外,还可以通过并行改串行的思路来解决.这种思想常见的实践方式就是数据库锁和消息队列的方式.这种方式的缺点是需要排队,响应速度慢,优点是节省 ...
- 利用redis + lua解决抢红包高并发的问题
抢红包的需求分析 抢红包的场景有点像秒杀,但是要比秒杀简单点.因为秒杀通常要和库存相关.而抢红包则可以允许有些红包没有被抢到,因为发红包的人不会有损失,没抢完的钱再退回给发红包的人即可.另外像小米这样 ...
- java高级精讲之高并发抢红包~揭开Redis分布式集群与Lua神秘面纱
java高级精讲之高并发抢红包~揭开Redis分布式集群与Lua神秘面纱 redis数据库 Redis企业集群高级应用精品教程[图灵学院] Redis权威指南 利用redis + lua解决抢红包高并 ...
- JAVA构建高并发商城秒杀系统——架构分析
面试场景 我们打算组织一个并发一万人的秒杀活动,1元秒杀100个二手元牙刷,你给我说说解决方案. 秒杀/抢购业务场景 商品秒杀.商品抢购.群红包.抢优惠劵.抽奖....... 秒杀/抢购业务特点 秒杀 ...
- Java Web(1)高并发业务
互联网无时无刻不面对着高并发问题,例如商品秒杀.微信群抢红包.大麦网抢演唱会门票等. 当一个Web系统,在一秒内收到数以万计甚至更多的请求时,系统的优化和稳定是至关重要的. 互联网的开发包括Java后 ...
- Springcloud 微服务 高并发(实战1):第1版秒杀
疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列之15 [博客园总入口 ] 前言 前言 疯狂创客圈(笔者尼恩创建的高并发研习社群)Springcloud 高并发系列文章,将为大家介绍三个版 ...
- 高并发&高可用系统的常见应对策略
解耦神器:MQ MQ是分布式架构中的解耦神器,应用非常普遍.有些分布式事务也是利用MQ来做的.由于其高吞吐量,在一些业务比较复杂的情况,可以先做基本的数据验证,然后将数据放入MQ,由消费者异步去处理后 ...
- 高并发&高可用系统的常见应对策略 秒杀等-(阿里)
对于一个需要处理高并发的系统而言,可以从多个层面去解决这个问题. 1.数据库系统:数据库系统可以采取集群策略以保证某台数据库服务器的宕机不会影响整个系统,并且通过负载均衡策略来降低每一台数据库服务器的 ...
- JAVA架构师眼中的高并发架构,分布式架构 应用服务器集群
前言 高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等. 为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适 ...
随机推荐
- Python day 02 知识点学习
1.格式化输出中,如果想单纯打出%,可以在%后面再跟一个%来转义达到效果.如下图: 2.while else 循环中,如果while循环被 break 打断,不会执行else结果,如下图: 初始编码 ...
- Vscode插件离线安装教程+中文插件安装失败解决方案
参考地址:https://blog.csdn.net/r657225738/article/details/108460875
- 收集的sql经典语句
经典SQL语句大全 一.基础1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql serve ...
- bert一些思考
bert结构 首先是embdding lookup,[batch * seq]-->[batch, seq, hidden] 然后是加个mask embdding和type embdding和p ...
- js根据输入天数,通过时间戳转日期时间,日期时间转时间戳,换算成多少天
1.时间戳转日期时间 function timestampToDate(timestamp,index) { var date = new Date(timestamp + index * 8 ...
- vue npm安装指令汇总
1.elmentui:npm i element-ui -S 2.打印插件:npm install vue-print-nb --save 3.时间转换插件Moment:npm install mom ...
- 用bcftools将多个vcf文件合并成一个vcf文件 或将多个vcf和合并成的vcf文件拆分成单个样本的vcf文件
1. 软件的安装 a. bcftools 的安装 b. bgzip的安装: https://blog.csdn.net/weixin_30471065/article/details/95108525 ...
- 解决IOS上传竖向照片会旋转90度的问题
// 解决IOS上传竖向照片会旋转90度的问题 rotate() { const that = this; that.imgOrientation = 1; let Orientation = nul ...
- 基于vue2.0创建vue项目
一.安装node环境 1.下载地址为:https://nodejs.org/en/ 2.检查是否安装成功:如果输出版本号,说明我们安装node环境成功 3.为了提高我们的效率,可以使用淘宝的镜像:ht ...
- vue移动端登录与登录保持
成品效果 首先进入首页点击右下角个人中心,若状态为登录中则进入个人中心页面,否则进入登录页 实现步骤 首先完成静态的登录页与个人中心页面 登录页 <template> <div cl ...