很抱歉,您提供的信息不完整,我无法直接给出答案。请您提供更具体的问题或信息,这样我才能更好地帮助您。

2026-03-30 15:181阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1245个文字,预计阅读时间需要5分钟。

很抱歉,您提供的信息不完整,我无法直接给出答案。请您提供更具体的问题或信息,这样我才能更好地帮助您。

前言:下面是Redis分布式锁常用概念说明:设置、获取、过期时间、删除。

1、Setnx 命令:SETNX key value

说明:将 key 的值设置为 value,当且仅当 key 不存在。若给定的 key 已经存在,则该命令不做任何操作。

前言

下面是Redis分布式锁常用的概念说明:设置、获取、过期时间、删除。

1、 Setnx

  • 命令:SETNX key value
  • 说明:将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。 时间复杂度:O(1)
  • 返回值:设置成功,返回1 ; 设置失败,返回 0

2、Getset

  • 命令:GETSET key value
  • 说明:将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。 时间复杂度:O(1)
  • 返回值:返回给定 key 的旧值; 当 key 没有旧值时,也即是, key 不存在时,返回 nil 。

3、Expire

  • 命令:EXPIRE key seconds
  • 说明:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。 时间复杂度:O(1)
  • 返回值:设置成功返回 1 ;当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。

4、Del

  • 命令:DEL key [key ...]
  • 说明:删除给定的一个或多个 key 。不存在的 key 会被忽略。 时间复杂度:O(N); N 为被删除的 key 的数量。删除单个字符串类型的 key ,时间复杂度为O(1)。 删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为O(M), M为以上数据结构内的元素数量。

锁的分类说明:

相对方 相对方 悲观锁 乐观锁 公平锁 非公平锁 独享锁 共享锁 线程锁 进程锁

一、CSRedis执行Lua脚本实现商品秒杀

以下以.NET 7控制台为实例测试

1.单线程模拟多线程进行秒杀

using CSRedis; Console.WriteLine("Hello World!"); //连接redis客户端 CSRedisClient redisClient = new CSRedisClient("127.0.0.1:6379,defaultDatabase=1"); //锁键 var lockKey = "lockKey"; //库存数 var stockKey = "stock"; //设置库存数量为5 redisClient.Set(stockKey, 5);//商品库存 //lua脚本,也可以通过流形式加载进来 var releaseLockScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";//释放锁的redis脚本 redisClient.Del(lockKey);//测试前,先把锁删了. //------------------Parallel可以控制线程的执行顺序----------------------------------- //ParallelOptions parallelOptions = new ParallelOptions(); //parallelOptions.MaxDegreeOfParallelism = 2;//最大并行数 //Parallel.For(0, 10, parallelOptions, t => this.DoSomethingLong($"btnParallel_Click_{t}")); Parallel.For(0, 10, i => { var id = Guid.NewGuid().ToString("N"); //获取锁,有效期5秒,防止死锁产生 do { //set : key存在则失败,不存在才会成功,并且过期时间5秒 var success = redisClient.Set(lockKey, id, expireSeconds: 5, exists: RedisExistence.Nx); if (success == true) { break; } Thread.Sleep(TimeSpan.FromSeconds(1));//休息1秒再尝试获取锁 } while (true); Console.WriteLine($"线程:{Task.CurrentId} 拿到了锁,开始消费"); //扣减库存 var currentStock = redisClient.IncrBy(stockKey, -1); if (currentStock < 0) { Console.WriteLine($"库存不足,线程:{Task.CurrentId} 抢购失败!"); redisClient.Eval(releaseLockScript, lockKey, id); return; } //模拟处理业务,这里不考虑失败的情况 Thread.Sleep(TimeSpan.FromSeconds(new Random().Next(1, 3))); Console.WriteLine($"线程:{Task.CurrentId} 消费完毕!剩余 {currentStock} 个"); //业务处理完后,释放锁. redisClient.Eval(releaseLockScript, lockKey, id); });

2.多线程进行秒杀

运行两个进程测试秒杀情况

using CSRedis; Thread.Sleep(500); Console.WriteLine("Hello World!"); CSRedisClient redisClient = new CSRedisClient("127.0.0.1:6379,defaultDatabase=1"); var lockKey = "lockKey"; //库存数 var stockKey = "stock"; //设置库存数量为5 redisClient.Set(stockKey, 10000, exists: RedisExistence.Nx);//商品库存 for (int i = 0; i < 100; i++) { Thread.Sleep(500); var releaseLockScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";//释放锁的redis脚本 var id = Guid.NewGuid().ToString("N"); //set : key存在则失败,不存在才会成功,并且不过期 var success = redisClient.Set(lockKey, id, expireSeconds: -1, exists: RedisExistence.Nx); if (success != true) { Console.WriteLine("当前资源以被占用,没机会了,等10秒钟再次尝试"); Thread.Sleep(1000);//休息1秒再尝试获取锁 continue; } else { Console.WriteLine($"线程:{Task.CurrentId} 拿到了锁,开始消费"); } ///业务操作 var currentStock = redisClient.IncrBy(stockKey, -1); if (currentStock < 0) { Console.WriteLine($"库存不足,线程:{Task.CurrentId} 抢购失败!"); redisClient.Eval(releaseLockScript, lockKey, id); return; } //模拟处理业务,这里不考虑失败的情况 Thread.Sleep(TimeSpan.FromSeconds(new Random().Next(1, 3))); Console.WriteLine($"线程:{Task.CurrentId} 消费完毕!剩余 {currentStock} 个"); //业务处理完后,释放锁. redisClient.Eval(releaseLockScript, lockKey, id); }

很抱歉,您提供的信息不完整,我无法直接给出答案。请您提供更具体的问题或信息,这样我才能更好地帮助您。

本文共计1245个文字,预计阅读时间需要5分钟。

很抱歉,您提供的信息不完整,我无法直接给出答案。请您提供更具体的问题或信息,这样我才能更好地帮助您。

前言:下面是Redis分布式锁常用概念说明:设置、获取、过期时间、删除。

1、Setnx 命令:SETNX key value

说明:将 key 的值设置为 value,当且仅当 key 不存在。若给定的 key 已经存在,则该命令不做任何操作。

前言

下面是Redis分布式锁常用的概念说明:设置、获取、过期时间、删除。

1、 Setnx

  • 命令:SETNX key value
  • 说明:将 key 的值设为 value ,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。 时间复杂度:O(1)
  • 返回值:设置成功,返回1 ; 设置失败,返回 0

2、Getset

  • 命令:GETSET key value
  • 说明:将给定 key 的值设为 value ,并返回 key 的旧值(old value)。当 key 存在但不是字符串类型时,返回一个错误。 时间复杂度:O(1)
  • 返回值:返回给定 key 的旧值; 当 key 没有旧值时,也即是, key 不存在时,返回 nil 。

3、Expire

  • 命令:EXPIRE key seconds
  • 说明:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。 时间复杂度:O(1)
  • 返回值:设置成功返回 1 ;当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。

4、Del

  • 命令:DEL key [key ...]
  • 说明:删除给定的一个或多个 key 。不存在的 key 会被忽略。 时间复杂度:O(N); N 为被删除的 key 的数量。删除单个字符串类型的 key ,时间复杂度为O(1)。 删除单个列表、集合、有序集合或哈希表类型的 key ,时间复杂度为O(M), M为以上数据结构内的元素数量。

锁的分类说明:

相对方 相对方 悲观锁 乐观锁 公平锁 非公平锁 独享锁 共享锁 线程锁 进程锁

一、CSRedis执行Lua脚本实现商品秒杀

以下以.NET 7控制台为实例测试

1.单线程模拟多线程进行秒杀

using CSRedis; Console.WriteLine("Hello World!"); //连接redis客户端 CSRedisClient redisClient = new CSRedisClient("127.0.0.1:6379,defaultDatabase=1"); //锁键 var lockKey = "lockKey"; //库存数 var stockKey = "stock"; //设置库存数量为5 redisClient.Set(stockKey, 5);//商品库存 //lua脚本,也可以通过流形式加载进来 var releaseLockScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";//释放锁的redis脚本 redisClient.Del(lockKey);//测试前,先把锁删了. //------------------Parallel可以控制线程的执行顺序----------------------------------- //ParallelOptions parallelOptions = new ParallelOptions(); //parallelOptions.MaxDegreeOfParallelism = 2;//最大并行数 //Parallel.For(0, 10, parallelOptions, t => this.DoSomethingLong($"btnParallel_Click_{t}")); Parallel.For(0, 10, i => { var id = Guid.NewGuid().ToString("N"); //获取锁,有效期5秒,防止死锁产生 do { //set : key存在则失败,不存在才会成功,并且过期时间5秒 var success = redisClient.Set(lockKey, id, expireSeconds: 5, exists: RedisExistence.Nx); if (success == true) { break; } Thread.Sleep(TimeSpan.FromSeconds(1));//休息1秒再尝试获取锁 } while (true); Console.WriteLine($"线程:{Task.CurrentId} 拿到了锁,开始消费"); //扣减库存 var currentStock = redisClient.IncrBy(stockKey, -1); if (currentStock < 0) { Console.WriteLine($"库存不足,线程:{Task.CurrentId} 抢购失败!"); redisClient.Eval(releaseLockScript, lockKey, id); return; } //模拟处理业务,这里不考虑失败的情况 Thread.Sleep(TimeSpan.FromSeconds(new Random().Next(1, 3))); Console.WriteLine($"线程:{Task.CurrentId} 消费完毕!剩余 {currentStock} 个"); //业务处理完后,释放锁. redisClient.Eval(releaseLockScript, lockKey, id); });

2.多线程进行秒杀

运行两个进程测试秒杀情况

using CSRedis; Thread.Sleep(500); Console.WriteLine("Hello World!"); CSRedisClient redisClient = new CSRedisClient("127.0.0.1:6379,defaultDatabase=1"); var lockKey = "lockKey"; //库存数 var stockKey = "stock"; //设置库存数量为5 redisClient.Set(stockKey, 10000, exists: RedisExistence.Nx);//商品库存 for (int i = 0; i < 100; i++) { Thread.Sleep(500); var releaseLockScript = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";//释放锁的redis脚本 var id = Guid.NewGuid().ToString("N"); //set : key存在则失败,不存在才会成功,并且不过期 var success = redisClient.Set(lockKey, id, expireSeconds: -1, exists: RedisExistence.Nx); if (success != true) { Console.WriteLine("当前资源以被占用,没机会了,等10秒钟再次尝试"); Thread.Sleep(1000);//休息1秒再尝试获取锁 continue; } else { Console.WriteLine($"线程:{Task.CurrentId} 拿到了锁,开始消费"); } ///业务操作 var currentStock = redisClient.IncrBy(stockKey, -1); if (currentStock < 0) { Console.WriteLine($"库存不足,线程:{Task.CurrentId} 抢购失败!"); redisClient.Eval(releaseLockScript, lockKey, id); return; } //模拟处理业务,这里不考虑失败的情况 Thread.Sleep(TimeSpan.FromSeconds(new Random().Next(1, 3))); Console.WriteLine($"线程:{Task.CurrentId} 消费完毕!剩余 {currentStock} 个"); //业务处理完后,释放锁. redisClient.Eval(releaseLockScript, lockKey, id); }

很抱歉,您提供的信息不完整,我无法直接给出答案。请您提供更具体的问题或信息,这样我才能更好地帮助您。