有问必答

摘要

本文将介绍如何使用Go语言的并发原语来构建一个简单的高并发秒杀系统。

我们将使用Go语言的原生库和一些常见的技术手段,包括互斥锁、通道、计数器等,来解决并发访问和数据一致性的问题。

本文只是一个简单的示例,重点是Go语言并发原语在业务场景中的应用。

在实际应用中,还需要考虑数据库事务、分布式锁、限流等问题。我之前也写过一篇文章,附在了文末。

1. 引言

秒杀系统是一种高并发场景下的特殊应用,需要处理大量的并发请求和保证数据的一致性。本文将介绍如何使用Go语言的并发原语来构建一个高并发的秒杀系统,以满足用户的需求并保证系统的稳定性。

2. 架构设计

我们的秒杀系统将采用经典的客户端-服务器架构。客户端发送秒杀请求,服务器处理请求并更新库存。为了保证系统的高并发性能,我们将使用以下技术和原语:

  • 互斥锁(sync.Mutex):用于保护共享资源的并发访问。
  • 通道(channel):用于协程间的通讯。
  • 计数器(sync.WaitGroup):用于等待所有请求完成。

3. 实现步骤

下面是我们实现秒杀系统的关键步骤:

3.1 初始化库存

在系统启动时,我们需要初始化商品的库存。

var stock = 100 // 商品库存
var mu sync.Mutex

3.2 处理秒杀请求

当客户端发送秒杀请求时,服务器需要处理请求并更新库存。

func handleRequest(user int) {
defer wg.Done()
if tryAcquireLock() {
if stock > 0 {
// 执行秒杀逻辑
stock--
fmt.Printf("用户%d秒杀成功,剩余库存:%d\n", user, stock)
} else {
fmt.Printf("用户%d秒杀失败,库存不足\n", user)
}
releaseLock()
} else {
fmt.Printf("用户%d未获取到锁,秒杀失败\n", user)
}
}

3.3 并发控制和等待

为了控制并发请求的数量,我们使用计数器和通道来限制并发度。

var wg sync.WaitGroup

func main() {
for i := 1; i <= 1000; i++ {
wg.Add(1)
go handleRequest(i)
}
wg.Wait()
}

3.4 互斥锁和并发安全

为了保证并发访问的安全性,我们使用互斥锁来保护共享资源的访问。

注意:TryLock()是go1.18才引入的

func tryAcquireLock() bool {
return mu.TryLock()
} func releaseLock() {
mu.Unlock()
}

4. 完整代码

package main

import (
"fmt"
"sync"
) //后面开启了1000个goroutine,所以这里channel的缓冲区设置成了1000
var ch = make(chan bool, 1000) type Product struct {
sync.Mutex
stock int64 // 商品库存
} func main() {
p := Product{stock: 1000}
for i := 1; i <= 1000; i++ {
go p.handleRequest(i)
}
<-ch
} func (p *Product) handleRequest(user int) {
if p.tryAcquireLock() {
if p.stock > 0 {
// 执行秒杀逻辑
p.stock--
fmt.Printf("用户%d秒杀成功,剩余库存:%d\n", user, p.stock)
} else {
fmt.Printf("用户%d秒杀失败,库存不足\n", user)
}
//这里是不可以使用defer的,因为可能会加锁失败,unlock一个不存在的锁
p.releaseLock()
} else {
fmt.Printf("用户%d未获取到锁,秒杀失败\n", user)
}
} func (p *Product) tryAcquireLock() bool {
//p.TryLock() 方法用于尝试获取锁,如果成功获取到锁,则相当于执行了 Lock() 操作,即加锁成功。
return p.TryLock()
} func (p *Product) releaseLock() {
p.Unlock()
ch <- true
}

解析代码

var ch = make(chan bool, 1000):后面开启了1000个goroutine,所以这里channel的缓冲区设置成了1000

p.releaseLock():这里是不可以使用defer的,因为可能会加锁失败,unlock一个不存在的锁

p.TryLock():方法用于尝试获取锁,如果成功获取到锁,则相当于执行了 Lock() 操作,即加锁成功。

5. 运行结果

6. 总结

通过使用Go语言的并发原语,我们成功地构建了一个高并发的秒杀系统。

使用互斥锁和计数器等原语,我们实现了并发控制、数据一致性和并发安全。这些原语帮助我们解决了高并发场景下的并发访问问题,并保证了系统的稳定性和性能。

本文只是一个简单的示例,实际的秒杀系统可能涉及更多的业务逻辑和并发控制。

在实际应用中,还需要考虑数据库事务、分布式锁、限流等问题。因此,建议根据实际需求和场景进行更详细的设计和实现。

我之前也有写万字长文总结过,感兴趣的朋友欢迎查看:万字详解:秒杀系统设计

一起学习

欢迎大家关注我的账号,你的支持,是我更文的最大动力!

也欢迎关注我的公众号: 程序员升职加薪之旅,领取更多Go学习和面试资料。

微信号:wangzhongyang1993

「有问必答」秒杀系统 Go并发编程实践!的更多相关文章

  1. PHP秒杀系统-高并发高性能的极致挑战

    慕课网实战教程后端:1.java c++算法与数据结构2.java Spring Boot带前后端 渐进式开发企业级博客系统3.java Spring Boot企业微信点餐系统4.java Sprin ...

  2. LibreOJ2097 - 「CQOI2015」任务查询系统

    Portal Description 给出\(n(n\leq10^5)\)个任务,和总时间范围\(m(m\leq10^5)\).每个任务有开始/结束时间\(s_i,e_i(1\leq s_i \leq ...

  3. PHP秒杀系统 高并发 高性能的极致挑战 下载

    第1章 课程介绍 秒杀系统在各种网站和应用中经常会用到.本课程从基本的系统设计和基础功能开始教导大家用PHP来设计和实现秒杀系统,并且为海量并发提供更高级的技术方案和实现手段. 第2章 系统技术选型分 ...

  4. 「CQOI2015」任务查询系统

    「CQOI2015」任务查询系统 传送门 好像也是板子题??? 区间修改,单点查询,考虑差分. 然后每次查询时就直接在对应的主席树上二分即可. 参考代码: #include <cstdio> ...

  5. [Java 并发] Java并发编程实践 思维导图 - 第一章 简单介绍

    阅读<Java并发编程实践>一书后整理的思维导图.

  6. [Java 并发] Java并发编程实践 思维导图 - 第二章 线程安全性

    依据<Java并发编程实践>一书整理的思维导图.

  7. 并发编程实践五:ReentrantLock

    ReentrantLock是一个可重入的相互排斥锁,实现了接口Lock,和synchronized相比,它们提供了同样的功能.但ReentrantLock使用更灵活.功能更强大,也更复杂.这篇文章将为 ...

  8. 并发编程实践三:Condition

    Condition实例始终被绑定到一个锁(Lock)上.Lock替代了Java的synchronized方法,而Condition则替代了Object的监视器方法,包含wait.notify和noti ...

  9. 读Java并发编程实践中,向已有线程安全类添加功能--客户端加锁实现示例

    在Java并发编程实践中4.4中提到向客户端加锁的方法.此为验证示例,写的不好,但可以看出结果来. package com.blackbread.test; import java.util.Arra ...

  10. [Java 并发] Java并发编程实践 思维导图 - 第四章 对象的组合

    依据<Java并发编程实践>一书整理的思维导图. 第一部分: 第二部分:

随机推荐

  1. 如何正确使用:has和:nth-last-child

    我们可以用CSS检查,以了解一组元素的数量是否小于或等于一个数字.例如,一个拥有三个或更多子项的grid.你可能会想,为什么需要这样做呢?在某些情况下,一个组件或一个布局可能会根据子元素的数量而改变. ...

  2. 浏览器工作原理及V8引擎

    浏览器解析过程 当浏览器加载html资源时,会进行如下的解析过程 遇见 HTML 标记,构建 DOM 树 遇见 style/link 标记调用相应解析器处理CSS标记,并构建出CSS样式树 遇见 sc ...

  3. [数据分析与可视化] Python绘制数据地图5-MovingPandas绘图实例

    MovingPandas是一个基于Python和GeoPandas的开源地理时空数据处理库,用于处理移动物体的轨迹数据.关于MovingPandas的使用见文章:MovingPandas入门指北,本文 ...

  4. .NET Core WebAPI 基础 文件上传

    昨天分享了一个在WebApi中如何接收参数的文章 .NET API 中的 FromRoute.FromQuery.FromBody 用法 - 一事冇诚 - 博客园 (cnblogs.com),然后有新 ...

  5. Web项目如何配置Eslint

    介绍 ESLint 是一个根据方案识别并报告 ECMAScript/JavaScript 代码问题的工具,其目的是使代码风格更加一致并避免错误.在很多地方它都与 JSLint 和 JSHint 类似, ...

  6. python基础:元组(tuple)列表(list)介绍

    一,元组 1.元组的创建(可以把元组看作一个容器,任何数据类型都可以放在里面)通过赋值方法创建元组In [5]: t = ("hello",2.3,2,True,{1:" ...

  7. NineData SQL 窗口支持深色模式,让程序员不再怕长期用眼!

    您有没有尝试过被明亮的显示器闪瞎眼的经历? 在夜间或低光环境下,明亮的界面会导致许多用眼健康问题,例如长时间使用导致的眼睛疲劳.干涩和不适感,同时夜间还可能会抑制褪黑素分泌,给您的睡眠质量带来影响. ...

  8. vim vimtutor

    =============================================================================== =      歡     迎     閱 ...

  9. [WUSTCTF 2020]朴实无华

    打开网页,就显示一个Hack me ,查看源码也是啥也没有,就用御剑扫一下 发现存在robots.txt文件 根据提示,打开/fAke_f1agggg.php 还真就一个错误的flag 仔细看了看,居 ...

  10. salesforce零基础学习(一百三十三)ListView的button思考

    本篇参考: salesforce零基础学习(九十五)lightning out salesforce零基础学习(一百一十)list button实现的一些有趣事情 https://help.sales ...