高并发的限流例子
总体思路是这样:
1. 用一个环形来代表通过的请求容器。
2. 用一个指针指向当前请求所到的位置索引,来判断当前请求时间和当前位置上次请求的时间差,依此来判断是否被限制。
3. 如果请求通过,则当前指针向前移动一个位置,不通过则不移动位置
4. 重复以上步骤 直到永远.......
以下代码的核心思路是这样的:指针当前位置的时间元素和当前时间的差来决定是否允许此次请求,这样通过的请求在时间上表现的比较平滑。
//限流组件,采用数组做为一个环
class LimitService
{
//当前指针的位置
int currentIndex = 0;
//限制的时间的秒数,即:x秒允许多少请求
int limitTimeSencond = 1;
//请求环的容器数组
DateTime?[] requestRing = null;
//容器改变或者移动指针时候的锁
object objLock = new object();
public LimitService(int countPerSecond,int _limitTimeSencond)
{
requestRing = new DateTime?[countPerSecond];
limitTimeSencond= _limitTimeSencond;
}
//程序是否可以继续
public bool IsContinue()
{
lock (objLock)
{
var currentNode = requestRing[currentIndex];
//如果当前节点的值加上设置的秒 超过当前时间,说明超过限制
if (currentNode != null&& currentNode.Value.AddSeconds(limitTimeSencond) >DateTime.Now)
{
return false;
}
//当前节点设置为当前时间
requestRing[currentIndex] = DateTime.Now;
//指针移动一个位置
MoveNextIndex(ref currentIndex);
}
return true;
}
//改变每秒可以通过的请求数
public bool ChangeCountPerSecond(int countPerSecond)
{
lock (objLock)
{
requestRing = new DateTime?[countPerSecond];
currentIndex = 0;
}
return true;
}
//指针往前移动一个位置
private void MoveNextIndex(ref int currentIndex)
{
if (currentIndex != requestRing.Length - 1)
{
currentIndex = currentIndex + 1;
}
else
{
currentIndex = 0;
}
}
}
测试程序如下:
static LimitService l = new LimitService(1000, 1);
static void Main(string[] args)
{
int threadCount = 50;
while (threadCount >= 0)
{
Thread t = new Thread(s =>
{
Limit();
});
t.Start();
threadCount--;
}
Console.Read();
}
static void Limit()
{
int i = 0;
int okCount = 0;
int noCount = 0;
Stopwatch w = new Stopwatch();
w.Start();
while (i < 1000000)
{
var ret = l.IsContinue();
if (ret)
{
okCount++;
}
else
{
noCount++;
}
i++;
}
w.Stop();
Console.WriteLine($"共用{w.ElapsedMilliseconds},允许:{okCount}, 拦截:{noCount}");
}
转载于:https://mp.weixin.qq.com/s/xIEN_IvR8h-Yc7oZoojTpw