C# 使用Parallel並行對比lock鎖和ConcurrentQueue併發性能

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        private static object o = new object();

        private static Queue<Product> _ProductsNormal { get; set; }
        private static Queue<Product> _Products { get; set; }
        private static ConcurrentQueue<Product> _ConcurrenProducts { get; set; }

        /*  -------------------------------------------
         *  對比lock鎖和ConcurrentQueue併發性能
         *  -------------------------------------------
            在.NET Framework4.0以後的版本中提供了命名空間:System.Collections.Concurrent 來解決線程安全和lock鎖性能問題,通過這個命名空間,能訪問以下爲併發做好了準備的集合。
            1.BlockingCollection 與經典的阻塞隊列數據結構類似,能夠適用於多個任務添加和刪除數據,提供阻塞和限界能力。
            2.ConcurrentBag 提供對象的線程安全的無序集合
            3.ConcurrentDictionary  提供可有多個線程同時訪問的鍵值對的線程安全集合
            4.ConcurrentQueue   提供線程安全的先進先出集合
            5.ConcurrentStack   提供線程安全的後進先出集合
            這些集合通過使用比較並交換和內存屏障等技術,避免使用典型的互斥重量級的鎖,從而保證線程安全和性能。
         */
        static void Main(string[] args)
        {
            #region 不啓用並行計算使用鎖lock
            //休眠重置校準結果
            Thread.Sleep(1000);
            _ProductsNormal = new Queue<Product>();

            Stopwatch swTaskn = new Stopwatch();//用於統計時間消耗的
            swTaskn.Start();
            Task tn1 = Task.Factory.StartNew(() => { AddProductsNormal(); });
            Task tn2 = Task.Factory.StartNew(() => { AddProductsNormal(); });
            Task tn3 = Task.Factory.StartNew(() => { AddProductsNormal(); });
            Task tn4 = Task.Factory.StartNew(() => { AddProductsNormal(); });
            Task tn5 = Task.Factory.StartNew(() => { AddProductsNormal(); });
            Task.WaitAll(tn1, tn2, tn3, tn4, tn5);
            swTaskn.Stop();

            Console.WriteLine("=========================不啓用並行計算使用鎖lock==================================");
            Console.WriteLine("Queue<Product> 當前數據量爲:" + _ProductsNormal.Count);
            Console.WriteLine("Queue<Product> 執行時間爲:" + swTaskn.ElapsedMilliseconds);
            #endregion

            #region 啓用並行計算使用鎖lock
            //休眠重置校準結果
            Thread.Sleep(1000);
            _Products = new Queue<Product>();

            Stopwatch swTask = new Stopwatch();//用於統計時間消耗的
            swTask.Start();
            Task t1 = Task.Factory.StartNew(() => { AddProducts(); });
            Task t2 = Task.Factory.StartNew(() => { AddProducts(); });
            Task t3 = Task.Factory.StartNew(() => { AddProducts(); });
            Task t4 = Task.Factory.StartNew(() => { AddProducts(); });
            Task t5 = Task.Factory.StartNew(() => { AddProducts(); });
            Task.WaitAll(t1, t2, t3, t4, t5);
            swTask.Stop();

            Console.WriteLine("=========================啓用並行計算使用鎖lock==================================");
            Console.WriteLine("Queue<Product> 當前數據量爲:" + _Products.Count);
            Console.WriteLine("Queue<Product> 執行時間爲:" + swTask.ElapsedMilliseconds);
            #endregion

            #region 啓用並行計算不使用鎖,使用4.0後提供的新功能
            //休眠重置校準結果
            Thread.Sleep(1000);
            _ConcurrenProducts = new ConcurrentQueue<Product>();

            Stopwatch swTask1 = new Stopwatch();
            swTask1.Start();
            Task tk1 = Task.Factory.StartNew(() => { AddConcurrenProducts(); });
            Task tk2 = Task.Factory.StartNew(() => { AddConcurrenProducts(); });
            Task tk3 = Task.Factory.StartNew(() => { AddConcurrenProducts(); });
            Task tk4 = Task.Factory.StartNew(() => { AddConcurrenProducts(); });
            Task tk5 = Task.Factory.StartNew(() => { AddConcurrenProducts(); });
            Task.WaitAll(tk1, tk2, tk3, tk4, tk5);
            swTask1.Stop();

            Console.WriteLine("===========啓用並行計算不使用鎖,使用4.0後提供的新功能==============================");
            Console.WriteLine("ConcurrentQueue<Product> 當前數據量爲:" + _ConcurrenProducts.Count);
            Console.WriteLine("ConcurrentQueue<Product> 執行時間爲:" + swTask1.ElapsedMilliseconds);
            #endregion

            Console.ReadLine();
        }


        static void AddProductsNormal()
        {            
            for (int i = 0; i < 1000000; i++)
            {
                Product product = new Product() { Name = "name" + i, Category = "Category" + i, SellPrice = 1 };
                lock (o)
                {
                    _ProductsNormal.Enqueue(product);
                }
            }
        }

        static void AddProducts()
        {
            Parallel.For(0, 1000000, (i) =>
            {
                Product product = new Product() { Name = "name" + i, Category = "Category" + i, SellPrice = 1 };
                lock (o)
                {
                    _Products.Enqueue(product);
                }
            });
        }

        static void AddConcurrenProducts()
        {
            Parallel.For(0, 1000000, (i) =>
            {
                Product product = new Product() { Name = "name" + i, Category = "Category" + i, SellPrice = 1 };
                _ConcurrenProducts.Enqueue(product);
            });
        }
    }

    class Product
    {
        public string Name { get; set; }
        public string Category { get; set; }
        public int SellPrice { get; set; }
    }
}

           /*
                Parallel在循環中的每個任務很簡單,耗時很小時,並不具備優勢,反而因爲多線程開銷導致效率低下。
                但在每個任務耗時較大時,應該使用Parallel,實現併發,具備很大的優勢             
             */
            var dt = DateTime.Now;
            var rand = new Random();
            for (int i = 0; i < 200; i++)
            {
                Thread.Sleep(rand.Next(10, 100));
            }

            var standerTime = (DateTime.Now - dt).TotalMilliseconds;
            Console.WriteLine("標準的for循環,耗時{0}毫秒", standerTime);


            dt = DateTime.Now;
            int count = 0;
            Parallel.For(0, 200, i =>
            {
                //輕量級鎖
                Interlocked.Increment(ref count);
                Thread.Sleep(rand.Next(10, 100));
            });
            Console.WriteLine("循環次數" + count);
            var parallelTime = (DateTime.Now - dt).TotalMilliseconds;
            Console.WriteLine("並行的for循環,耗時{0}毫秒", parallelTime);
            Console.WriteLine();

            if (standerTime <= parallelTime)
            {
                Console.WriteLine("----------標準的for循環節省{0}毫秒----------", (parallelTime - standerTime));
            }
            else
            {
                Console.WriteLine("----------並行的for循環節省{0}毫秒----------", (standerTime - parallelTime));
            }


            //Console.WriteLine(result.Result.ToString());
            Console.ReadLine();

 

發佈了271 篇原創文章 · 獲贊 287 · 訪問量 309萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章