news 2026/4/18 19:11:23

Redis 解锁:C++ 实战深度探索 Set 数据类型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis 解锁:C++ 实战深度探索 Set 数据类型

你的标题是“Redis 解锁:C++ 实战深度探索 Set 数据类型”,看起来像是想深入探讨 Redis 的Set数据类型在 C++ 中的实战用法,同时可能把“解锁”理解为“解锁分布式锁”的意思(因为 Redis 分布式锁和 SET 命令关系非常密切),或者单纯想全面掌握 Set 类型。

下面我把两个方向都给你讲清楚,并重点用redis-plus-plus(目前最流行的 C++ Redis 客户端)来写实战代码。

1. Redis Set 数据类型核心特性与典型用法

Redis 的 Set 是无序、不重复的字符串集合,底层实现有两种:

  • intset(小集合 + 全是整数时)
  • hashtable(ziplist 编码已废弃,新版用 dict)

常用命令(时间复杂度几乎都是 O(1) 或 O(N) 很小):

命令作用时间复杂度示例
SADD添加一个或多个元素O(1)SADD myset “apple” “banana”
SREM删除元素O(1)SREM myset “apple”
SISMEMBER判断元素是否存在O(1)SISMEMBER myset “apple”
SCARD获取集合元素个数O(1)SCARD myset
SMEMBERS获取所有元素O(N)SMEMBERS myset
SRANDMEMBER随机返回一个/多个元素O(1) / O(N)SRANDMEMBER myset 3
SPOP随机弹出并删除元素O(1)SPOP myset
SUNION并集O(N)SUNION set1 set2
SINTER交集O(N)SINTER set1 set2
SDIFF差集O(N)SDIFF set1 set2

典型业务场景

  • 抽奖系统(随机抽取用户)
  • 标签系统(用户打标签,去重)
  • 共同好友、共同关注
  • 访问用户去重(UV 统计)
  • 黑名单 / 白名单
  • 秒杀商品库存校验(但更常用 string 或 lua)

2. C++ 中使用 redis-plus-plus 操作 Set(推荐方式)

先安装 redis-plus-plus(基于 hiredis,线程安全,支持连接池)

# 假设你用 vcpkg 或自己编译vcpkginstallredis-plus-plus

基本连接与 Set 操作示例

#include<sw/redis++/redis++.h>#include<iostream>#include<vector>#include<string>usingnamespacesw::redis;intmain(){try{// 单节点连接(推荐使用连接池)ConnectionOptions opts;opts.host="127.0.0.1";opts.port=6379;// opts.password = "yourpass"; // 如有密码// 连接池(生产推荐)ConnectionPoolOptions pool_opts;pool_opts.size=16;// 连接数pool_opts.wait_timeout=std::chrono::milliseconds(100);pool_opts.connection_timeout=std::chrono::seconds(5);autoredis=Redis(RedisURI("tcp://127.0.0.1:6379"),pool_opts);// --------------------- Set 操作 ---------------------std::string key="myset:fruits";// 清空测试数据(慎用生产环境)redis.del(key);// SADD 添加元素(支持批量)longlongcnt=redis.sadd(key,{"apple","banana","orange","apple"});// apple 只加一次std::cout<<"Added "<<cnt<<" unique elements\n";// 输出 3// SISMEMBER 判断存在if(redis.sismember(key,"banana")){std::cout<<"banana exists\n";}// SCARD 元素个数std::cout<<"Size: "<<*redis.scard(key)<<"\n";// 3// SMEMBERS 获取全部(小心大集合)std::vector<std::string>members;redis.smembers(key,std::back_inserter(members));std::cout<<"All members: ";for(constauto&m:members)std::cout<<m<<" ";std::cout<<"\n";// SRANDMEMBER 随机取(不删除)autorand_one=redis.srandmember(key);if(rand_one)std::cout<<"Random: "<<*rand_one<<"\n";// SPOP 随机弹出并删除autopopped=redis.spop(key);if(popped)std::cout<<"Popped: "<<*popped<<"\n";// SREM 删除redis.srem(key,"orange");// 集合运算示例redis.sadd("set:a",{"1","2","3","4"});redis.sadd("set:b",{"3","4","5","6"});std::vector<std::string>inter;redis.sinter({"set:a","set:b"},std::back_inserter(inter));std::cout<<"Intersection: ";for(auto&v:inter)std::cout<<v<<" ";// 3 4std::cout<<"\n";}catch(constError&e){std::cerr<<"Redis error: "<<e.what()<<std::endl;return1;}return0;}

3. Redis 分布式锁才是“解锁”最经典的场景(SET + NX + PX)

Redis 官方推荐的单节点分布式锁就是用SET命令(不是 Set 类型,而是 String 类型):

SET lock:order:12345 "uuid-xxx-clientA" NX PX 30000
  • NX:不存在才设置(加锁)
  • PX:毫秒级过期(防死锁)
  • value 必须唯一(通常是 UUID + 客户端标识)

C++ 实现简单版分布式锁(非 Redlock)

#include<sw/redis++/redis++.h>#include<string>#include<random>#include<chrono>#include<thread>classSimpleRedisLock{private:Redis&_redis;std::string _lock_key;std::string _lock_value;std::chrono::milliseconds _expire_ms;public:SimpleRedisLock(Redis&r,conststd::string&key,intexpire_seconds=30):_redis(r),_lock_key(key),_expire_ms(std::chrono::seconds(expire_seconds)){}booltry_lock(){// 生成唯一 value(简单示例,可用 uuid 库)std::random_device rd;std::mt19937gen(rd());std::uniform_int_distribution<>dis(10000000,99999999);_lock_value="client-"+std::to_string(dis(gen));autoreply=_redis.set(_lock_key,_lock_value,std::chrono::duration_cast<std::chrono::milliseconds>(_expire_ms),UpdateType::ONLY_IF_NOT_EXIST);// 等价 NXreturnreply&&*reply;// true 表示加锁成功}boolunlock(){// 安全解锁:用 Lua 脚本保证原子性staticconstchar*lua_script=R"( if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end )";autores=_redis.eval<longlong>(lua_script,{_lock_key},{_lock_value});returnres&&*res==1;}~SimpleRedisLock(){unlock();// 析构自动尝试释放(视业务可去掉)}};// 使用示例voidprocess_order(Redis&redis){SimpleRedisLocklock(redis,"lock:order:12345",30);if(!lock.try_lock()){std::cout<<"获取锁失败\n";return;}std::cout<<"获得锁,开始处理订单...\n";std::this_thread::sleep_for(std::chrono::seconds(5));// 模拟业务lock.unlock();std::cout<<"订单处理完成,已释放锁\n";}

更安全的做法

  • 用 redis-plus-plus 自带的Redlock(多节点)
  • 或引入Redisson的思想,用更完善的续期机制(watchdog)
// redis-plus-plus 内置 Redlock 用法(需多个 master 节点)autoredlock=Redlock({node1,node2,node3,node4,node5});if(redlock.lock("my-resource",std::chrono::seconds(30))){// 业务redlock.unlock();}

总结对比

需求推荐数据类型核心命令C++ 库支持度
去重、标签、抽奖SetSADD / SPOP / SRANDMEMBER非常好
分布式锁(单节点)StringSET NX PX优秀
高可用分布式锁StringRedlock 算法redis++ 支持
排行榜Sorted SetZADD / ZRANGE-

如果你真正想问的是Set 类型的深度实战,还是分布式锁的 C++ 实现,可以再补充具体场景,我可以继续给你更细致的代码或优化方案(Lua 续期、Redlock 完整实现、 fencing token 等)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:46:35

C语言鼠标钩子源码实现与全局监控教程

鼠标钩子是Windows系统提供的一种机制&#xff0c;允许应用程序监视或拦截系统中的鼠标消息。理解其源码实现&#xff0c;对于开发需要全局鼠标监控、自定义鼠标行为或制作辅助工具的程序至关重要。本文将围绕C语言实现鼠标钩子的几个核心环节展开。 鼠标钩子是什么 从编程角度…

作者头像 李华
网站建设 2026/4/18 2:46:18

无需专业设备:GLM-Image WebUI在普通电脑上的运行指南

无需专业设备&#xff1a;GLM-Image WebUI在普通电脑上的运行指南 1. 前言&#xff1a;让AI图像生成触手可及 你是否曾经被那些惊艳的AI生成图像所吸引&#xff0c;却因为听说需要昂贵的专业显卡而望而却步&#xff1f;或者你尝试过一些在线AI绘画工具&#xff0c;但又担心隐…

作者头像 李华
网站建设 2026/4/17 22:32:06

Lingyuxiu MXJ LoRA保姆级教程:打造你的专属人像风格

Lingyuxiu MXJ LoRA保姆级教程&#xff1a;打造你的专属人像风格 你是否也曾羡慕那些社交媒体上风格统一、质感高级的人像照片&#xff1f;无论是清新自然的日系写真&#xff0c;还是光影柔和的唯美肖像&#xff0c;背后往往都有一套独特的视觉语言。今天&#xff0c;我要带你…

作者头像 李华
网站建设 2026/4/16 11:02:03

零基础教程:用Lingyuxiu MXJ LoRA轻松创作写真级人像

零基础教程&#xff1a;用Lingyuxiu MXJ LoRA轻松创作写真级人像 想用AI画出媲美专业摄影的唯美人像&#xff0c;却苦于复杂的模型部署和参数调整&#xff1f;今天&#xff0c;我们就来手把手教你&#xff0c;如何通过一个名为“Lingyuxiu MXJ LoRA创作引擎”的镜像&#xff0…

作者头像 李华
网站建设 2026/4/16 13:07:41

不用PS!亚洲美女-造相Z-Turbo快速生成商业级人像照片

不用PS&#xff01;亚洲美女-造相Z-Turbo快速生成商业级人像照片 你是否还在为一张高质量的亚洲女性人像图反复打开Photoshop、调整图层、修皮肤、换背景、调光影&#xff1f;是否试过多个AI绘图工具&#xff0c;却总在“亚洲特征不明显”“眼神空洞”“肤色失真”“职业感不足…

作者头像 李华