秒杀业务优化之从分布式锁到基于消息队列的异步秒杀
一、业务场景介绍
优惠券、门票等限时抢购常常出现在各类应用中,这样的业务一般为了引流宣传而降低利润,所以一旦出现问题将造成较大损失,那么在业务中就要求我们对这类型商品严格限时、限量、每位用户限一次、准确无误的创建订单,这样的要求看似简单,但在分布式系统中,要求我们充分考虑高并发下的线程安全问题,今天我们来看一下两种解决思路。
二、基于Redisson分布式锁的秒杀方案
这里我们就不进行自定义redis锁了,Redisson 基于 Redis 实现了 Java 驻内存数据网格(In-Memory Data Grid),它不仅提供了对 Redis 原生命令的封装,还提供了一系列高级的分布式数据结构和服务,促进使用者对 Redis 的关注分离,让开发者能够更专注于业务逻辑,所以我们直接使用Redisson,但底层源码还是需要我们去自己学习掌握的。
1.流程概览
其实单看流程图我们就能发现这一连串的串行逻辑就会非常影响效率,我们先留着这个问题后面优化 。
2.具体实现
@Overridepublic Result generate(Long voucherId) {//查询优惠券SeckillVoucher voucher = seckillVoucherService.getById(voucherId);//活动是否开始/结束if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {return Result.fail("活动未开始!");}if (voucher.getEndTime().isBefore(LocalDateTime.now())) {return Result.fail("活动已结束!");}//库存表是否充足if (voucher.getStock()<1) {return Result.fail("库存不足!");}Long userId = UserHolder.getUser().getId();//只锁同一个id//创建锁对象RLock lock = redissonClient.getLock("lock:order:" + userId);//获取锁,防止同一用户的并发请求boolean isLock = lock.tryLock();//默认不等待,30秒过期if (!isLock) {//获取锁失败return Result.fail("网络繁忙!");}//拿到spring事务代理,这里为了简单解决事务自调用直接去拿代理可能造成问题,建议将事务方法重构至另一服务类并注入try {IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();return proxy.createVoucherOrder(voucherId);} finally {//释放锁lock.unlock();}}@Transactional//要锁住事物,防止事物在锁释放后才提交导致其他线程进入public Result createVoucherOrder(Long voucherId) {Long userId = UserHolder.getUser().getId();//一人一单int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();if (count >0) {return Result.fail("您最多只可购买一单!");}//扣减库存boolean flag = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherId).gt("stock",0).update();if (!flag){//高并发下已经被其他用户线程扣减return Result.fail("库存不足2!");}//创建订单VoucherOrder voucherOrder = new VoucherOrder();//唯一IDlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);//用户idvoucherOrder.setUserId(userId);//代金券IdvoucherOrder.setVoucherId(voucherId);save(voucherOrder);//返回订单IDreturn Result.ok(orderId);}
3.测试分析
接下来我们登录数据库中所有的用户并记录Authorization
@SpringBootTest
@Component
public class SecKill {@Autowiredprivate IUserService userService;@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid userLogin() throws IOException {// 定义保存 token 的文件路径String filePath = "D:\\tokens.txt";// 使用 BufferedWriter 写入文件try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) { // 追加模式for (User user : userService.list()) {String phone = user.getPhone();HttpSession session = null;userService.sendCode(phone, session);String code = stringRedisTemplate.opsForValue().get("login:code:" + phone);LoginFormDTO loginFormDTO = new LoginFormDTO();loginFormDTO.setCode(code);loginFormDTO.setPhone(phone);String token = userService.logIn(loginFormDTO, session);// 将 token 写入文件writer.write(token);writer.newLine(); // 换行writer.flush(); // 刷新缓冲区,确保数据写入文件}} catch (IOException e) {e.printStackTrace();}}
}
然后我们设置优惠券数量为200,通过jmeter(一款测试工具,大家自行学习如何使用)模拟数据库中1000多个用户总计每秒1000的高并发请求
从聚合报告中可以看到虽然80%的异常率确实满足了我们对优惠券的限量要求,通过查看数据库订单和库存也不存在问题,但是我们可以看到我们的平均响应时间在高并发下达到了344ms,吞吐量只有1200左右,如果面临更高的并发难免因性能局限出现问题。
三、基于消息队列的异步秒杀
1.问题分析
正如我们一开始发现的,每个请求来到服务器都需要执行一串的数据库读写操作,而写操作耗时是比较久的,可是当我们确定用户抢单成功后只要能确保订单最终写入即可,无需让其阻塞请求,所以我们其实可以将读写操作分离开。
我们可以利用读操作完成下单资格的各种校验,校验成功即可对请求做出响应,那么后续写订单操作怎么完成呢?我们需要根据校验成功的记录完成写操作,那谁来完成校验成功的记录呢,这样记录是不是又和原来的读写串行一样了呢?
2.工具对比
首先我们的目的是加快请求响应效率,减轻数据库压力,其实我们需要的就是一个中间工具做到能够快速存储校验成功的记录并有限制的可控的逐渐将存储起来的记录转发给数据库让其创建订单,能做到上述要求的工具有很多,这里简单对比以下三种供大家参考。
特性/技术 | 阻塞队列 | Redis | MQ消息中间件(如RabbitMQ、Kafka) |
---|---|---|---|
系统解耦 | 低,主要用于单机环境 | 中,支持集群部署 | 高,天然用于系统解耦 |
异步通信 | 支持,但需要手动实现 | 通过发布/订阅模式实现 | 专为异步通信设计 |
削峰填谷 | 临时存储请求,能力有限 | 缓存请求,需合理设计策略 | 缓存大量请求,后端按速率消费 |
可靠性和持久性 | 依赖具体实现,需额外持久化 | 支持持久化,可靠性较高 | 高可靠性和持久性,支持消息确认 |
性能和吞吐量 | 受限于单机处理能力 | 性能较高,支持集群 | 最高,适用于大规模分布式系统 |
功能丰富性 | 单一,主要用于线程间通信 | 支持多种数据结构和操作 | 支持多种消息协议、路由机制等 |
开发和维护成本 | 低,但需手动实现异步逻辑 | 中等,易于实现和使用 | 高,需学习和理解相关协议和机制 |
适用场景 | 小规模、单机环境 | 中小规模、集群部署 | 大规模分布式系统、复杂路由 |
3.流程概览
由于阻塞队列局限较大,MQ中间件比较简单,这里我们以Redis中的stream为例(除此之外,list和PubSub也能实现,但是局限较大)实现异步秒杀。
对于红框部分,为了确保原子性,我们借助lua脚本完成,这样一来我们就将MySQL的读写操作分离开来,请求响应中只需要读取验证,用redis更高效的io操作完成简单记录,随后异步逐渐处理MySQl的订单写入。
4.具体实现
- lua脚本
--- --- Generated by EmmyLua(https://github.com/EmmyLua) --- Created by cds. --- DateTime: 2025/3/23 13:03 --- --1.参数列表 --1.1优惠券id local voucherId=ARGV[1] --1.2用户id local userId=ARGV[2] --1.3订单id local orderId=ARGV[3]--2.数据key --2.1库存key local stockKey='seckill:stock:' .. voucherId --2.2订单key local orderKey='seckill:order:' .. voucherId--脚本业务 --判断库存是否充足 if (tonumber(redis.call('get',stockKey))<=0) then--库存不足返回1return 1 end --判断用户是否下单 if (redis.call('sismember',orderKey,userId)==1) then--下过单返回2return 2 end --扣库存 redis.call('incrby',stockKey,-1) --下单 redis.call('sadd',orderKey,userId) --发送消息到消息队列 xadd stream.orders * k1 v1 k2 v2 .. redis.call('xadd','stream.orders','*','userId',userId,'voucherId',voucherId,"id",orderId)return 0
- 具体业务
@Autowiredprivate IVoucherOrderService proxy;//初始化lua脚本信息private static final DefaultRedisScript<Long> SECKILL_SCRIPT;static {SECKILL_SCRIPT =new DefaultRedisScript<>();SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));SECKILL_SCRIPT.setResultType(Long.class);}//异步单例线程private static final ExecutorService SECKILL_ORDER_EXECTUOR= Executors.newSingleThreadExecutor();//在spring的Bean初始化并注入后开始@PostConstructprivate void init(){SECKILL_ORDER_EXECTUOR.submit(new VoucherOrderHandler());}//线程任务private class VoucherOrderHandler implements Runnable {String queueName = "stream.orders";@Overridepublic void run() {while (true) {try {//获取消息队列中的订单信息 XREAD GROUP group1 c1 count 1 block 2000 streams stream.orders >List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(Consumer.from("group1", "c1"),StreamReadOptions.empty().count(1).block(Duration.ofSeconds(2)),StreamOffset.create(queueName, ReadOffset.lastConsumed()));//判断消息是否获取成if (list == null || list.isEmpty()) {//获取失败 没有消息,继续循环continue;}//获取成功,可以下单//解析消息中的订单信息MapRecord<String, Object, Object> record = list.get(0);Map<Object, Object> value = record.getValue();VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);handleVoucherOrder(voucherOrder);//ACK确认 SACK stream.orders group1 idstringRedisTemplate.opsForStream().acknowledge(queueName, "group1", record.getId());} catch (Exception e) {log.error("创建订单异常{}", e.getMessage());//有异常去pendingList拿handlePendingList();}}}private void handlePendingList() {while (true) {try {//获取pending-list队列中的订单信息 XREAD GROUP group1 c1 count 1 block 2000 streams stream.orders 0List<MapRecord<String, Object, Object>> list = stringRedisTemplate.opsForStream().read(Consumer.from("group1", "c1"),StreamReadOptions.empty().count(1),StreamOffset.create(queueName, ReadOffset.from("0")));//判断消息是否获取成if (list == null || list.isEmpty()) {//获取失败 pending-list没有消息,结束循环break;}//获取成功,可以下单//解析消息中的订单信息MapRecord<String, Object, Object> record = list.get(0);Map<Object, Object> value = record.getValue();VoucherOrder voucherOrder = BeanUtil.fillBeanWithMap(value, new VoucherOrder(), true);handleVoucherOrder(voucherOrder);//ACK确认 SACK stream.orders group1 idstringRedisTemplate.opsForStream().acknowledge(queueName, "group1", record.getId());} catch (Exception e) {log.error("创建订单异常{}", e.getMessage());try {Thread.sleep(20);} catch (InterruptedException ex) {throw new RuntimeException(ex);}}}}}private void handleVoucherOrder(VoucherOrder voucherOrder) {Long userId = voucherOrder.getUserId();//创建锁对象RLock lock = redissonClient.getLock("lock:order:" + userId);//获取锁boolean isLock = lock.tryLock();//默认不等待,30秒过期if (!isLock) {//获取锁失败log.info("请勿重复购买!");return;}//拿到spring事务代理try {proxy.createVoucherOrder(voucherOrder);} finally {//释放锁lock.unlock();}}//这部分的检验是以防stream消息队列里出现问题导致重复save操作@Transactional//要锁住事物public void createVoucherOrder(VoucherOrder voucherOrder) {Long userId = voucherOrder.getUserId();//一人一单int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder.getVoucherId()).count();if (count > 0) {log.error("您最多只可购买一单!");return;}//扣减库存boolean flag = seckillVoucherService.update().setSql("stock=stock-1").eq("voucher_id", voucherOrder.getVoucherId()).gt("stock", 0).update();if (!flag) {log.info("库存不足!");return;}//创建订单save(voucherOrder);}}@Overridepublic Result secKill(Long voucherId) {//查询优惠券SeckillVoucher voucher = seckillVoucherService.getById(voucherId);//活动是否开始/结束if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {return Result.fail("活动未开始!");}if (voucher.getEndTime().isBefore(LocalDateTime.now())) {return Result.fail("活动已结束!");}//库存表是否充足if (voucher.getStock() < 1) {return Result.fail("库存不足!");}//获取用户Long userId = UserHolder.getUser().getId();//1执行lua脚本//唯一IDlong orderId = redisIdWorker.nextId("order");Long result = stringRedisTemplate.execute(SECKILL_SCRIPT,Collections.emptyList(),voucherId.toString(), userId.toString(), String.valueOf(orderId));int r = result.intValue();//2判断lua脚本返回值0if (r != 0) {//2.1不为零无资格return Result.fail(r == 1 ? "库存不足!" : "不能重复下单!");}return Result.ok(orderId);}
5.测试分析
我们再次使用jmeter进行同样的测试,但这次我们需要提前将库存信息同步到redis
可以看到经过优化的秒杀业务吞吐量大大增加,平均响应时间降低到30ms左右,得到了十倍左右的提升,大大增加了响应处理效率
redis订单记录
redis消息队列记录
如果去控制台观察日志可以发现,删改请求少量穿插在中间,大部分聚集在查询校验结束的末尾,读操作基本都聚集在最前面,DB操作得到有效控制,这就是异步写入处理的体现
好了,本次分享到这里结束,谢谢阅读!
相关文章:
秒杀业务优化之从分布式锁到基于消息队列的异步秒杀
一、业务场景介绍 优惠券、门票等限时抢购常常出现在各类应用中,这样的业务一般为了引流宣传而降低利润,所以一旦出现问题将造成较大损失,那么在业务中就要求我们对这类型商品严格限时、限量、每位用户限一次、准确无误的创建订单,…...
【CGE】社会核算矩阵构建(一):SAM基本结构
【CGE】社会核算矩阵构建(一):SAM基本结构 社会核算矩阵构建(一):SAM基本结构一、SAM的概念和基本特点二、SAM的基本结构1.开放经济体的SAM表结构2.SAM表各账户的主要核算内容(1)社会…...
蓝桥杯算法实战分享:算法进阶之路与实战技巧
引言 蓝桥杯作为国内极具影响力的程序设计竞赛,为众多编程爱好者和专业人才提供了展示自我的舞台。参与蓝桥杯不仅能检验自身编程水平,还能拓宽技术视野,为未来职业发展积累宝贵经验。本文将结合历年真题与参赛经验,全面分享蓝桥…...
自定义minshell
我们在前面已经了解了进程的概念,以及如何进行进程控制。接下来我们就使用这些知识,来自己实现一个shell即命令行解释器!!! 一.打印命令行提示符 我们在使用Linux操作系统时,一登陆就会启动bash进程——命…...
坦克大战(c++)
今天我给大家分享一个c游戏。 废话不多说,作品展示: #include <stdio.h> #include <windows.h> #include <time.h> //里规格:长39*278 (真坐标)(假坐标宽为39) 高39 //外规格:长…...
《可爱风格 2048 游戏项目:HTML 实现全解析》
一、引言 在如今的数字化时代,小游戏以其简单易上手、趣味性强的特点深受大家喜爱。2048 游戏作为一款经典的数字合并游戏,拥有庞大的玩家群体。本文将详细介绍一个用单文件 HTML 实现的可爱风格 2048 游戏项目,它不仅具备传统 2048 游戏的基…...
C++ 利用类模板实现一个数组类封装
案例描述: 实现一个通用的数组类,要求如下: 可以对内置数据类型以及自定义数据类型的数据进行存储 将数组中的数据存储到堆区 构造函数中可以传入数组的容量 提供对应的拷贝构造函数以及operator防止浅拷贝问题 提供尾插法和尾删法对数组…...
【AndroidRTC-11】如何理解webrtc的Source、TrackSink
Android-RTC系列软重启,改变以往细读源代码的方式 改为 带上实际问题分析代码。增加实用性,方便形成肌肉记忆。同时不分种类、不分难易程度,在线征集问题切入点。 问题1:如何理解VideoSource、VideoTrack&VideoSink三者的关系…...
数据类设计_图片类设计之9_图标类设计_C++实战_(前端架构)
前言 学的东西多了,要想办法用出来.C和C是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容 引入 前面写了矩阵图形类对象和像素图形类对象,本贴通过一个快捷方式图标类的设计,来继续数据类型设计的一些讨论. 快捷方式图标是这个样子: 属性分析 首先,快捷方式…...
fuse性能关键参数entry_timeout
entry_timeout 是 FUSE(Filesystem in Userspace)中的一个选项,用于控制目录项缓存的有效期。具体来说,它决定了文件系统在多长时间内缓存目录项(如文件名到 inode 的映射),从而影响文件系统的性…...
3. 轴指令(omron 机器自动化控制器)——>MC_ResetFollowingError
机器自动化控制器——第三章 轴指令 13 MC_ResetFollowingError变量▶输入变量▶输出变量▶输入输出变量 功能说明▶指令详情▶时序图▶重启动运动指令▶多重启运动指令▶异常 MC_ResetFollowingError 对指令当前位置和反馈当前位置的偏差进行复位。 指令名称FB/FUN图形表现S…...
Spring Boot项目快速创建-开发流程(笔记)
主要流程: 前端发送网络请求->controller->调用service->操纵mapper->操作数据库->对entity数据对象赋值->返回前端 前期准备: maven、mysql下载好 跟学视频,感谢老师: https://www.bilibili.com/video/BV1gm4…...
[操作系统] 进程间通信:进程池的实现
引言 在学习操作系统时,进程间通信(IPC)和多进程管理是核心内容之一。进程池是一种常见的模式,通过预先创建一组工作进程来处理任务,避免频繁创建和销毁进程带来的开销。本文将详细剖析一个用 C 实现的进程池代码&…...
信号相关的程序
1、不断打印*换行之后响应信号,然后循环 #include <stdio.h> #include <string.h> #include <signal.h> #include <stdlib.h> #include <unistd.h> static void alrm_handler(int signo) {write(1,"!",1); }int main( in…...
【计算机网络】-计算机网络期末复习题复习资料
一、计算机网络体系结构(800字) 1. OSI参考模型 七层结构:物理层→数据链路层→网络层→传输层→会话层→表示层→应用层 各层核心功能: 物理层:比特流传输(如RJ45、光纤接口) 数据链路层&…...
Linux 基础入门操作 第十二章 TINY Web 服务器
1 服务器基础架构 1.1 背景知识 Web 服务器使用 HTTP 协议与客户端(即浏览器)通信,而 HTTP 协议又基于 TCP/IP 协议。因此我们要做的工作就是利用 Linux 系统提供的 TCP 通信接口来实现 HTTP 协议。 而 Linux 为我们提供了哪些网络编程接口…...
L2-052 吉利矩阵
L2-052 吉利矩阵 - 团体程序设计天梯赛-练习集 这道题打表 打表部分被注释了 n4 [0,0,282, 2008, 10147, 40176, 132724, 381424, 981541, 2309384] n3 [0,0,21, 55, 120, 231, 406, 666, 1035, 1540] n2 [0,0,3, 4, 5, 6, 7, 8, 9, 10] l,n map(int,input().split()) if…...
BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量时序光伏功率预测,附模型研究报告
BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量时序光伏功率预测,附模型研究报告 目录 BKA-CNN-LSTM、CNN-LSTM、LSTM、CNN四模型多变量时序光伏功率预测,附模型研究报告预测效果基本介绍程序设计参考资料 预测效果 基本介绍 BKA-CNN-LSTM、CNN-LSTM、…...
【读书笔记】华为《从偶然到必然》
note 华为的成功并非偶然,而是通过IPD体系、投资组合管理、平台战略等系统性工具,将研发投资转化为可持续的商业竞争力。书中强调的“管理即内部因素”理念,揭示了企业规模扩张与管理能力匹配的深层规律,为高科技企业提供了可借鉴…...
flink广播算子Broadcast
文章目录 一、Broadcast二、代码示例三.或者第二种(只读取一个csv文件到广播内存中)提示:以下是本篇文章正文内容,下面案例可供参考 一、Broadcast 为了关联一个非广播流(keyed 或者 non-keyed)与一个广播流(BroadcastStream),我们可以调用非广播流的方法 connect(),…...
实时图像处理:让你的应用更智能
I. 引言 实时图像处理在现代应用中扮演着重要的角色,它能够使应用更加智能、响应更加迅速。本文将深入探讨实时图像处理的原理、部署过程以及未来的发展趋势,旨在帮助开发者更好地理解如何将实时图像处理应用于他们的项目中。 II. 实时图像处理的基础概…...
深入理解 Linux 基础 IO:从文件操作到缓冲区机制
亲爱的读者朋友们😃,此文开启知识盛宴与思想碰撞🎉。 快来参与讨论💬,点赞👍、收藏⭐、分享📤,共创活力社区。 在 Linux 系统中,文件输入输出(IO)…...
汇编语言高级编程技巧:从基础到进阶
前言 汇编语言作为底层编程语言,直接操作硬件,执行效率高,但编写复杂逻辑时往往显得繁琐。通过使用汇编伪指令和宏,我们可以实现类似于高级语言的结构,如条件判断、循环、结构体和函数等,从而提升代码的可读…...
Android Studio常见问题解决
一、环境配置问题 1. 安装失败 问题描述:在安装过程中,可能会遇到硬件要求不符合、网络问题、安装包损坏、权限不足或安装路径问题等,导致安装失败。 解决方法: 硬件要求:确保设备满足最低硬件要求。 网络问题&…...
【RHCE】LVS-NAT模式负载均衡实验
目录 题目 IP规划 配置IP RS1 RS2 RS3 LVS client 配置RS 配置LVS 安装lvs软件 启动ipvsadm服务 lvs规则匹配 ipvsadm部分选项 客户端测试 总结 题目 使用LVS的 NAT 模式实现 3 台RS的轮询访问,IP地址和主机自己规划。 IP规划 主机IP地址RS1-nat模…...
MacOS下的IntelliJ IDEA突然无法访问本机的虚拟机
今天在开发的过程中,突然遇到一个怪事,之前运行的好好的程序,突然间报无法连接redis服务器,一开始以为是网络问题,在OS的terminal里又是ping 又是telnet的,一切正常,可是程序就是连不上。 挠了半…...
【渗透测试】Fastjson 反序列化漏洞原理(一)
目录 一、Fastjson 是什么二、Fastjson 工作原理三、反序列化漏洞原理1. 反序列化漏洞的定义2. Fastjson 的反序列化机制3. 漏洞成因关注以下几点(1) 动态类型解析(2) 自动调用方法(3) 信任用户输入 4. 漏洞利用过程(1) 寻找可利用的类(也称为 "Gadget"&a…...
BM100-K系列开关量输入信号隔离器
1. 产品概述 BM100-K系列开关量输入信号隔离器是一款高性能的信号处理设备,专为工业自动化控制系统设计。该产品支持干接点或NAMUR型接近开关输入,并通过继电器或晶体管实现隔离输出。其核心功能包括输入输出逻辑控制(同相/反相可调…...
c++11 | 细说智能指针
💓个人主页:mooridy 💓专栏地址:C 关注我🌹,和我一起学习更多计算机的知识 🔝🔝🔝 什么是智能指针? 智能指针是 C 中一种用于管理动态内存的机制。它提供了一…...
谷歌大型推理模型曝光!击败Claude-3.7-Thinking
哎!最近推特上的网友在LMSYS Arena 发现了个泄漏的大模型 Nebula,效果据说特别好,打败了o1、o3-mini、Claude 3.7 Thinking等模型: 网友们通过询问和分析 API,发现这似乎是谷歌正在秘密测试的新推理模型!推…...
Python FastAPI面试题及参考答案
目录 FastAPI 的优缺点是什么?列举典型应用场景。 解释 FastAPI 的路由机制,如何定义路径参数和查询参数? Pydantic 模型在 FastAPI 中的作用是什么?如何进行数据验证与序列化? FastAPI 如何自动生成 OpenAPI 文档?Swagger UI 和 ReDoc 的区别? 什么是 ASGI?FastAP…...
C++(初阶)(八)——string
string string遍历下标[]迭代器iterator反向迭代器 范围for修改 Capacitysize和lengthmax_sizecapacityclearcapacity的扩容reserveresize Element accessoperator[]和at **Modifiers**:appendinserterasereplace String operationsc_strsubstr和findfind_first_ofgetline 题目…...
计算机操作系统处理机调度(1)
系列文章目录 第三章:处理机调度与死锁 文章目录 系列文章目录前言一、作业和资源:二、处理机调度的层次: 1.高级调度2.初级调度3.中级调度 三、作业调度算法举例:总结 前言 在多道程序的环境下,内存中存在着多个进…...
ctfshow REVERSE re2 萌新赛 内部赛 七夕杯 WP
目录 re2 萌新赛 flag白给 签退 数学不及格 内部赛 批量生产的伪劣产品 来一个派森 好好学习 天天向上 屏幕裂开了 七夕杯 逆向签到 easy_magic re2 ida分析主函数,将flag.txt内容加密写入enflag.txt 这是密钥加密过程 标准rc4加密 简单异或解…...
云服务器怎么设置端口禁用呢?
在云服务器上禁用特定端口是提升安全性的重要措施,可通过云平台安全组和服务器本地防火墙双重配置实现。以下是详细操作指南: 一、通过云平台安全组禁用端口(优先推荐) 1. 莱卡云/腾讯云/华为云等操作步骤 登录云控制台 进入ECS实…...
V8引擎源码编译踩坑实录
背景 为了解决 view8 代码没有指定版本的 v8 引擎问题GitHub - suleram/View8: View8 - Decompiles serialized V8 objects back into high-level readable code. 但是打出来了exe文件也没啥用,不清楚这个view8是解决啥逆向用的,如果想逆向electron的j…...
享元模式(Flyweight Pattern)
享元模式(Flyweight Pattern)是一种结构型设计模式,它通过共享技术来高效地支持大量细粒度对象的复用。 一、基础 1 意图 运用共享技术有效地支持大量细粒度的对象 减少内存中对象的数量,节省系统资源 2 适用场景 一个应用程序使用了大量对象 由于对象数量庞大造成很大的…...
RAG(Retrieval-Augmented Generation)基建之PDF解析的“魔法”与“陷阱”
嘿,亲爱的算法工程师们!今天咱们聊一聊PDF解析的那些事儿,简直就像是在玩一场“信息捉迷藏”游戏!PDF文档就像是个调皮的小精灵,表面上看起来规规矩矩,但当你想要从它那里提取信息时,它就开始跟…...
搭建小程序该如何选择服务器?
当企业选择开发属于自己的小程序,则需要服务器的支持,服务器可以帮助加速小程序的上线速度,影响小程序后面的运行是否流畅,同时还会影响用户访问网站时的速度,所以,企业在搭建小程序时该如何选择合适的服务…...
【腾讯云架构师技术沙龙2025.03.22】
大模型技术演进与行业影响分析 日期:2025年3月22日 主讲人:李建忠 《DeepSeek实战驱动行业智变—AI应用寒武纪》 整理:飞书语音转化DeepSeek分析汇总 一、技术演进:从快思考到慢思考 1. 早期争议与能力局限(2022-202…...
【jvm】垃圾回收的并行和并发
目录 1. 说明2. 并行(Parallel)2.1 定义2.2 特点2.3 示例 3. 并发(Concurrent)3.1 定义3.2 特点3.3 示例 4. 并行与并发的比较 1. 说明 1.在JVM(Java虚拟机)的垃圾回收机制中,并行(…...
Flowable基础表结构
工作流程的相关操作都是操作存储在对应的表结构中,为了能更好的弄清楚Flowable的实现原理和细节,我们有必要先弄清楚Flowable的相关表结构及其作用。在Flowable中的表结构在初始化的时候会创建相关表结构,具体如下: ACT_EVT&…...
为什么不同的损失函数可以提升模型性能?
不同的损失函数可以提升模型性能的原因在于,损失函数是模型优化的核心目标,它直接定义了模型在训练过程中需要最小化的误差或偏差。通过设计不同的损失函数,可以针对具体任务的特点、数据分布的特性以及模型的目标需求进行更精确的优化&#…...
git上传文件到远程库
1.git init 把这个目录变成git可以管理的仓库 2.git status查看文件追踪的情况(工作区的文件是红色) 3.git add . 添加工作区所有文件到暂存区 再git status(此时文件都变成绿色) 4.git commit -m 描述性文字 5.git push -u o…...
【产品小白】需求分析的进阶
在产品经理的职业发展中,需求分析能力的提升至关重要。普通和进阶在需求分析层面,往往存在从表面需求到本质问题的认知差异。以下从几个方面探讨这一进阶过程: 1. 需求理解的深度 普通:通常停留在用户表达的显性需求层面&#…...
机试题汇总
万能头文件 #include<bits/stdc.h> 输入一个年份和月份,输出该月的天数 1.3.5.7.8.10.12 -- 31天 闰年判断: year % 400 0 || (year % 4 0 && year % 100 ! 0) 输入字符串,反转输出 #include<iostream&g…...
软件公司高新技术企业代办:机遇与陷阱并存-优雅草卓伊凡
软件公司高新技术企业代办:机遇与陷阱并存-优雅草卓伊凡 在科技飞速发展的当下,软件公司如雨后春笋般涌现,众多企业渴望通过申请高新技术企业来获得政策支持与发展助力。随之而来的,是高新技术企业代办业务的兴起。然而ÿ…...
C#中3维向量的实现
c#中默认不带库三维向量,需要自己安装第三方库,或者可以手动实现一个简易的三维向量。 public struct Vector3D {public double X { get; set; }public double Y { get; set; }public double Z { get; set; }public Vector3D(double x, double y, doubl…...
使用腾龙边缘计算网关内置的AIoTedge+NodeRED接入西门子PLC
腾龙边缘计算网关一体机凭借其强大的性能和丰富的功能,为企业提供了一种高效、灵活的解决方案。本文将详细介绍如何使用腾龙边缘计算网关一体机内置的AIoTedgeNodeRED接入西门子PLC,实现数据的采集、处理与传输。 一、硬件准备与环境搭建 在开始之前&am…...
基于MLA的人类语音情感分类
《DeepSeek大模型高性能核心技术与多模态融合开发(人工智能技术丛书)》(王晓华)【摘要 书评 试读】- 京东图书 随着信息技术的不断发展,如何让机器识别人类情绪,这个问题受到了学术界和工业界的广泛关注。目前,情绪识…...