当前位置: 首页 > article >正文

c# .NET 高级编程 高并发必备技巧 - 锁

 

锁 最为常见的应用就是 高并发的情况下,库存的控制。本次只做简单的单机锁介绍。
直接看代码:
每请求一次库存-1. 假如库存1000,在1000个人请求之后,库存将变为0。

     public int Reduce0(){int r = 0;string key = "stock";string stock = Rds.cli.Get(key);int.TryParse(stock, out r);if (r > 0){r--;Rds.cli.Set(key, r);}else{throw new Exception("库存用尽!");}return r;}

本次测试使用Jmeter进行测试。先初始化库存为1000。

Jmeter 设置如下,一个线程请求1000次,再去查看库存刚好为0,没有任何问题:

调整一下测试参数,5个人同时请求,各请求200次。再去查看库存

发现请求后,还有279的库存。明明请求了1000次。但是还有279的库存,明显不对。

造成次问题的原因很简单,就是在库存还没完全减的情况下,有另外一个、或多个线程同时发出了请求,而库存只减少了1

只要还有库存,就可以继续请求,到了库存完全为0的时候,已经超过1000个人进行了请求。与实际库存不符合。

为了解决这个问题。我们简单调整一下代码:

        private static object lck = new object();[HttpGet]public  int Reduce1(){lock(lck){int r = 0;string key = "stock";string stock = Rds.cli.Get(key);r = int.Parse(stock);if (r > 0){r--;Rds.cli.Set(key, r);}else{throw new Exception("库存用尽!");}return r;}}

声明一个静态变量,然后再方法体内 使用lock。调整代码后,再次进行测试:

发现 请求1000次后,库存为0。调整测试参数 100人*10次。测试结果依然为0。

到此为止,问题解决。

但是,实际应用场景中,高并发的应用,都会多机分布式部署。分布式部署要怎么解决?大家思考一下。

上一篇文章简单的介绍了单机的情况下如何进行加锁,防止高并发带来的问题。
然而现实中,一般会高并发的应用,很少会单机部署。当用户量达到一定的程度,分布式、集群部署是必然的选择。在分布式部署的情况下,之前的单机锁还会有效吗?代码还是之前的代码:

    private static object lck = new object();/// <summary>/// 单机锁/// </summary>/// <returns></returns>/// <exception cref="Exception"></exception>[HttpGet]public  int Reduce1(){lock(lck){int r = 0;string key = "stock";string stock = Rds.cli.Get(key);r = int.Parse(stock);if (r > 0){r--;Rds.cli.Set(key, r);}else{throw new Exception("库存用尽!");}return r;}} 

今天再来测试一下,首先在本机模拟分布式的部署。
api 部署3个,分别对应的端口 1020、1021、1022。使用nginx进行负载均衡转发,Nginx简单配置信息如下:
 


Jmeter请求的接口是nginx的8000,请求线程和上一次一样100*10
 


 


1000次请求后,再去查库存,发现库存并不为0。所以单机锁,在分布式的情况下,根本没起作用。

所以在分布式的情况下,必须要借助第三方的中间件。Redis是其中比较常见的解决方案,以下是简单的实现代码:

    /// <summary>/// 分布式锁/// </summary>/// <returns></returns>/// <exception cref="Exception"></exception>[HttpGet]public int Reduce2(){bool Lck1 =false;int r = 0;string identity=Guid.NewGuid().ToString(); //设置识别,避免错误释放锁。int OverTime = 10; //根据实际业务场景设置 超时时间,避免出现死锁try{Lck1 = Rds.cli.SetNx("lock", identity, OverTime);while (!Lck1){Lck1 = Rds.cli.SetNx("lock", identity, OverTime);}string key = "stock";string stock = Rds.cli.Get(key);r = int.Parse(stock);if (r > 0){r--;Rds.cli.Set(key, r);}else{throw new Exception("库存用尽!");}}catch (Exception ex){throw;}finally{string id = Rds.cli.Get("lock");if(id==identity){Rds.cli.Del("lock");}}return r;}

再次通过Jmeter 请求nginx 的端口。经过改造后的代码方法,在1000次请求后,库存已经为0。说明此次的分布式锁是有效的。

需要注意的是,要避免死锁,所以加锁的时候,要根据业务场景 设置 过期时间。
为了避免释放错误,加锁的时候也要加上身份认证。

好了此次关于锁的分享完毕。

转自:https://www.cnblogs.com/pzscit/p/17644157.html

http://www.lryc.cn/news/2419804.html

相关文章:

  • FFmpeg + Qt 音频文件转PCM数据
  • 1、 什么是time_wait?如何产生的?
  • HTTP Status 404 – Not Found 问题集合
  • 进程调度
  • 几个流行而其免费的SVN服务器
  • 计算机网络实训-2 网络设备配置基础
  • 第2期 Directory Opus(文件管理工具大搜全)
  • module是什么类型_Linux驱动开发:为什么教程都不讲MODULE_DEVICE_TABLE的作用
  • Free Pascal介绍
  • 蓝牙广播报文
  • 数据产品化的数据标准化:如何实现数据的一致性和可比性
  • 3维地图的尝试
  • C和指针
  • Ubuntu下Tinyos安装步骤
  • Java中获取时间以及java.util和java.sql之间时间日期的转换
  • assert_param 错误的解决方法
  • [Mysql] LIKE与通配符
  • 利用百度点击原理提升关键词排名
  • 禁用的灰色文本框、按钮的克星
  • web应用项目开发
  • window.open()和window.showModalDialog 的使用及传值操作
  • c语言程序的生命周期(编写、预处理、编译、汇编、链接、执行)
  • 四个数列(二分查找)
  • IoU,GIoU,DIoU、CIoU详解
  • System.ArgumentException HResult=-2147024809 Message=参数无效。 Source=System.Drawing
  • 标志位寄存器与CF、OF标志位的区分
  • 史上可以针对大部分对于鼠标右键菜单的设置
  • 常用协议对应的端口号
  • Javaweb开发项目之JS知识(JavaScript)
  • 日本推出罩杯测量APP,罩杯大小一夹便知!