高并发的限流例子

总体思路是这样:

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

posted @ 2019-02-28 10:27  Fate、狐狸  阅读(284)  评论(0编辑  收藏  举报