C#隊列Queue實現一個簡單的電商網站秒殺程序


電商的秒殺和搶購,對程序員來說,都不是一個陌生的東西。然而,從技術的角度來說,這對於Web系統是一個巨大的考驗。當一個Web系統,在一秒鍾內收到數以萬計甚至更多請求時,系統的優化和穩定至關重要。

我們直接將請求放入隊列Queue中的,采用FIFO(First Input First Output,先進先出),這樣的話,我們就不會導致某些請求永遠獲取不到鎖。這里有點強行將多線程變成單線程的感覺。

秒殺看似簡單,但是可能會存在兩個問題:高並發和超賣

高並發:比較火秒殺活動同時參與秒殺人數都是10w+的,如此之高的秒殺人數對於網站架構從前到后都是一種考驗。

超賣:秒殺商品都會有固定的數量,如何避免成功下訂單買到商品的人數不超過商品數量的上限,這是每個搶購活動都要面臨的一大難題。

此代碼簡單說明問題,例如有10萬個人秒殺10個商品,我們定義隊列queueAll 存放並發的10萬人,queueCur存放已經搶到的10個人

        private static int cnt =10;
        private static Queue<string> queueAll = new Queue<string>();
        private static Queue<string> queueCur = new Queue<string>();

購買代碼

        public RetData Buy(string uid)
        {
            queueAll.Enqueue(uid);

            if (queueAll.Count > cnt){
                return new RetData {Code = -1, Msg = "商品搶光了", Cnt = 0};
            }
            queueCur.Enqueue(uid);
            return new RetData { Code = 1, Msg = "恭喜已搶到", Cnt = cnt - queueAll.Count };
        }
        public class RetData
        {
            public int Code { get; set; }
            public string Msg { get; set; }
            public int Cnt { get; set; }
        }

處理訂單

        public static void HandleQueue()
        {
            Task.Factory.StartNew(() =>
            {
                while (true) if (queueCur.Count > 0) HandleOrder();
            });
        }

        public static void HandleOrder()
        {
            while (queueCur.Count != 0)
            {
                Console.WriteLine("處理用戶訂單中:" + queueCur.Dequeue());
            }
        }

Parallel模擬10萬用戶並發請求

            var tt = new ThreadPar();
            Parallel.For(0, 100000, (t, state) =>
            {
                var uid = "用戶" + t;
                var x = tt.Buy(uid);
                if (x.Code == -1)
                {
                    Console.WriteLine(uid + ":" + x.Msg);
                    //state.Break();
                }
                else
                    Console.WriteLine(uid + ":" + x.Msg + "還剩下:" + x.Cnt + "件");
            });

處理中,由於數據太多看不到誰搶到了商品,后面注釋了搶不到的輸出

用戶0、1、75000、50000、50001、50002 、50003 、50004、25000、75001 這10位搶到了商品,其他人都沒有搶到,

全部代碼示例:

    public class ThreadPar
    {
        private static int cnt =10;
        private static Queue<string> queueAll = new Queue<string>();
        private static Queue<string> queueCur = new Queue<string>();
        //private static  object ol = new object();

        static ThreadPar()
        {
            HandleQueue();
        }

        public RetData Buy(string uid)
        {
            queueAll.Enqueue(uid);

            if (queueAll.Count > cnt){
                return new RetData {Code = -1, Msg = "商品搶光了", Cnt = 0};
            }
            queueCur.Enqueue(uid);
            return new RetData { Code = 1, Msg = "恭喜已搶到", Cnt = cnt - queueAll.Count };
        }
        public class RetData
        {
            public int Code { get; set; }
            public string Msg { get; set; }
            public int Cnt { get; set; }
        }
        public static void HandleQueue()
        {
            Task.Factory.StartNew(() =>
            {
                while (true) if (queueCur.Count > 0) HandleOrder();
            });
        }

        public static void HandleOrder()
        {
            while (queueCur.Count != 0)
            {
                Console.WriteLine("處理用戶訂單中:" + queueCur.Dequeue());
            }
        }

    }
View Code
    class Program
    {
        static void Main()
        {
            ThreadBuy();

            Console.WriteLine("----------操作完成----------");
            Console.ReadKey();
        }

        //秒殺
        static void ThreadBuy()
        {
            System.Threading.Thread.Sleep(10000);
            var tt = new ThreadPar();
            Parallel.For(0, 1000000, (t, state) =>
            {
                var uid = "用戶" + t;
                var x = tt.Buy(uid);
                if (x.Code == -1)
                {
                    Console.WriteLine(uid + ":" + x.Msg);
                    //state.Break();
                }
                else
                {
                    Console.WriteLine(uid + ":" + x.Msg + "還剩下:" + x.Cnt + "");
                }
                    
            });

        }

    }
控制台程序

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM