C#並行編程-Parallel

菜鳥學習並行編程,參考《C#並行編程高級教程.PDF》,若有錯誤,歡迎指正。html

目錄

 

TPL中引入了一個新命名空間System.Threading.Tasks,在該命名空間下Task是主類,表示一個類的異步的併發的操做,建立並行代碼的時候不必定要直接使用Task類,在某些狀況下能夠直接使用Parallel靜態類(System.Threading.Tasks.Parallel)下所提供的方法,而不用底層的Task實例。學習

Parallel.Invoke  spa

試圖將不少方法並行運行,若是傳入的是4個方法,則至少須要4個邏輯內核才能足以讓這4個方法併發運行,邏輯內核也稱爲硬件線程。pwa

須要注意的是:1.即便擁有4個邏輯內核,也不必定可以保證所須要運行的4個方法可以同時啓動運行,若是其中的一個內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行。

                    2.經過Parallel.Invoke編寫的併發執行代碼必定不能依賴與特定的執行順序,由於它的併發執行順序也是不定的。

                    3.使用Parallel.Invoke方法必定要測量運行結果、實現加速比以及邏輯內核的使用率,這點很重要。

                    4.使用Parallel.Invoke,在運行並行方法前都會產生一些額外的開銷,如分配硬件線程等。

 

好處:這是一種並行運行不少方法的簡單方式,使用Parallel.Invoke,不須要考慮任務和線程的問題。

下面貼代碼:

    class Program
    {
        private static List<Product> ProductList = null;
        /*  coder:釋迦苦僧
         *  沒有特定的執行順序
         *  示例中 基於電腦配置 採用了4個方法的並行編程
         *  Parallel.Invoke 首先會嘗試並行啓動4個方法,充分利用一個或多個物理處理器所提供的多個邏輯內核
         *  可是在實際的並行執行中,至少要有4個邏輯內核才能知足4個方法的並行運行
         *  若是有個或者多個邏輯內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行
         *  經過Parallel.Invoke編寫的併發執行代碼必定不能依賴與特定的執行順序,由於它的併發執行順序也是不定的。
         */
        static void Main(string[] args)
        {
            ProductList = new List<Product>();
            Thread.Sleep(3000);
            Stopwatch swTask = new Stopwatch();
            swTask.Start();
            /*執行並行操做*/
            Parallel.Invoke(SetProcuct1_500, SetProcuct2_500, SetProcuct3_500, SetProcuct4_500);
            swTask.Stop();
            Console.WriteLine("500條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds);

            ProductList = new List<Product>();
            Thread.Sleep(3000);/*防止並行操做 與 順序操做衝突*/
            Stopwatch sw = new Stopwatch();
            sw.Start();
            SetProcuct1_500();
            SetProcuct2_500();
            SetProcuct3_500();
            SetProcuct4_500();
            sw.Stop();
            Console.WriteLine("500條數據  順序編程所耗時間:" + sw.ElapsedMilliseconds);

            ProductList = new List<Product>();
            Thread.Sleep(3000);
            swTask.Restart();
            /*執行並行操做*/
            Parallel.Invoke(() => SetProcuct1_10000(), () => SetProcuct2_10000(), () => SetProcuct3_10000(), () => SetProcuct4_10000());
            swTask.Stop();
            Console.WriteLine("10000條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds);

            ProductList = new List<Product>();
            Thread.Sleep(3000);
            sw.Restart();
            SetProcuct1_10000();
            SetProcuct2_10000();
            SetProcuct3_10000();
            SetProcuct4_10000();
            sw.Stop();
            Console.WriteLine("10000條數據 順序編程所耗時間:" + sw.ElapsedMilliseconds);

            Console.ReadLine();
        }
        private static void SetProcuct1_500()
        {
            for (int index = 1; index < 500; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct1 執行完成");
        }
        private static void SetProcuct2_500()
        {
            for (int index = 500; index < 1000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct2 執行完成");
        }
        private static void SetProcuct3_500()
        {
            for (int index = 1000; index < 2000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct3 執行完成");
        }
        private static void SetProcuct4_500()
        {
            for (int index = 2000; index < 3000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct4 執行完成");
        }
        private static void SetProcuct1_10000()
        {
            for (int index = 1; index < 20000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct1 執行完成");
        }
        private static void SetProcuct2_10000()
        {
            for (int index = 20000; index < 40000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct2 執行完成");
        }
        private static void SetProcuct3_10000()
        {
            for (int index = 40000; index < 60000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct3 執行完成");
        }
        private static void SetProcuct4_10000()
        {
            for (int index = 60000; index < 80000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct4 執行完成");
        }
    }

    class Product
    {
        public string Name { get; set; }

        public string Category { get; set; }

        public int SellPrice { get; set; }
    }
View Code

圖中咱們能夠看出利用 Parallel.Invoke編寫的併發執行代,它的併發執行順序也是不定的。
可是所執行的時間上比不採用並行編程所耗的時間差很少。

這是由於咱們在並行編程中操做了共享資源 ProductList ,若是我把代碼作出如下修改,採用並行編程的好處就顯現出來了。

    class Program
    { 
        /*  coder:釋迦苦僧
         *  沒有特定的執行順序
         *  示例中 基於電腦配置 採用了4個方法的並行編程
         *  Parallel.Invoke 首先會嘗試並行啓動4個方法,充分利用一個或多個物理處理器所提供的多個邏輯內核
         *  可是在實際的並行執行中,至少要有4個邏輯內核才能知足4個方法的並行運行
         *  若是有個或者多個邏輯內核處於繁忙狀態,那麼底層的調度邏輯可能會延遲某些方法的初始化執行
         *  經過Parallel.Invoke編寫的併發執行代碼必定不能依賴與特定的執行順序,由於它的併發執行順序也是不定的。
         */
        static void Main(string[] args)
        { 
            Thread.Sleep(3000);
            Stopwatch swTask = new Stopwatch();
            swTask.Start();
            /*執行並行操做*/
            Parallel.Invoke(SetProcuct1_500, SetProcuct2_500, SetProcuct3_500, SetProcuct4_500);
            swTask.Stop();
            Console.WriteLine("500條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds);
             
            Thread.Sleep(3000);/*防止並行操做 與 順序操做衝突*/
            Stopwatch sw = new Stopwatch();
            sw.Start();
            SetProcuct1_500();
            SetProcuct2_500();
            SetProcuct3_500();
            SetProcuct4_500();
            sw.Stop();
            Console.WriteLine("500條數據  順序編程所耗時間:" + sw.ElapsedMilliseconds);
             
            Thread.Sleep(3000);
            swTask.Restart();
            /*執行並行操做*/
            Parallel.Invoke(() => SetProcuct1_10000(), () => SetProcuct2_10000(), () => SetProcuct3_10000(), () => SetProcuct4_10000());
            swTask.Stop();
            Console.WriteLine("10000條數據 並行編程所耗時間:" + swTask.ElapsedMilliseconds);
             
            Thread.Sleep(3000);
            sw.Restart();
            SetProcuct1_10000();
            SetProcuct2_10000();
            SetProcuct3_10000();
            SetProcuct4_10000();
            sw.Stop();
            Console.WriteLine("10000條數據 順序編程所耗時間:" + sw.ElapsedMilliseconds);

            Console.ReadLine();
        }
        private static void SetProcuct1_500()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 1; index < 500; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct1 執行完成");
        }
        private static void SetProcuct2_500()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 500; index < 1000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct2 執行完成");
        }
        private static void SetProcuct3_500()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 1000; index < 2000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct3 執行完成");
        }
        private static void SetProcuct4_500()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 2000; index < 3000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct4 執行完成");
        }
        private static void SetProcuct1_10000()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 1; index < 20000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct1 執行完成");
        }
        private static void SetProcuct2_10000()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 20000; index < 40000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct2 執行完成");
        }
        private static void SetProcuct3_10000()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 40000; index < 60000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct3 執行完成");
        }
        private static void SetProcuct4_10000()
        {
            List<Product> ProductList = new List<Product>();
            for (int index = 60000; index < 80000; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
            }
            Console.WriteLine("SetProcuct4 執行完成");
        }
    }

    class Product
    {
        public string Name { get; set; }

        public string Category { get; set; }

        public int SellPrice { get; set; }
    }
View Code

我將每一個方法中的資源隔離,性能顯而易見。

可是在操做500條數據時,顯然採用並行操做並不明智,並行所帶來的損耗比較大,在實際的開發中,仍是要注意下是否有必要進行並行編程。

 

Parallel.For

將for循環替換成Parallel.For,並採用適合這個新方法的參數,就能夠對這個已有的for循環進行重構,使其可以充分利用並行化優點。

須要注意的是:1.Parallel.For不支持浮點數的步進,使用的是Int32或Int64,每一次迭代的時候加1

                    2.因爲循環體是並行運行,去迭代執行的順序沒法保證

下面貼代碼

    class Program
    {
        /*  coder:釋迦苦僧*/
        static void Main(string[] args)
        {
            Thread.Sleep(3000);
            ForSetProcuct_100();

            Thread.Sleep(3000);
            ParallelForSetProcuct_100();
            Console.ReadLine();
        }
        private static void ForSetProcuct_100()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            List<Product> ProductList = new List<Product>();
            for (int index = 1; index < 100; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
                Console.WriteLine("for SetProcuct index: {0}", index);
            }
            sw.Stop();
            Console.WriteLine("for SetProcuct 10 執行完成 耗時:{0}", sw.ElapsedMilliseconds);
        }
        private static void ParallelForSetProcuct_100()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            List<Product> ProductList = new List<Product>();
            Parallel.For(1, 100, index =>
            {

                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                ProductList.Add(model);
                Console.WriteLine("ForSetProcuct SetProcuct index: {0}", index);
            });
            sw.Stop();
            Console.WriteLine("ForSetProcuct SetProcuct 20000 執行完成 耗時:{0}", sw.ElapsedMilliseconds);
        }
    }

    class Product
    {
        public string Name { get; set; }

        public string Category { get; set; }

        public int SellPrice { get; set; }
    }
View Code

由圖中咱們能夠看出,使用Parallel.For所迭代的順序是沒法保證的。

Parallel.ForEach

Parallel.ForEach提供一個並行處理一組數據的機制,能夠利用一個範圍的整數做爲一組數據,而後經過一個自定義的分區器將這個範圍轉換爲一組數據塊,每一塊數據都經過循環的方式進行處理,而這些循環式並行執行的。

下面貼代碼:

    class Program
    {
        /*  coder:釋迦苦僧*/
        static void Main(string[] args)
        {
            List<Product> ProductList =GetProcuctList();
            Parallel.ForEach(ProductList, (model) => {
                Console.WriteLine(model.Name);
            });
            Console.ReadLine();
        }
        private static List<Product> GetProcuctList()
        { 
            List<Product> result = new List<Product>();
            for (int index = 1; index < 100; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                result.Add(model);
            }
            return result;
        } 
    }

    class Product
    {
        public string Name { get; set; }

        public string Category { get; set; }

        public int SellPrice { get; set; }
    }
View Code

ParallelLoopState

ParallelLoopState該實例提供瞭如下兩個方法用於中止 Parallel.For,Parallel.ForEach

Break-這個方法告訴並行循環應該在執行了當前迭代後儘快地中止執行。吐過調用Break時正在處理迭代100,那麼循環仍然會處理全部小於100的迭代。

Stop-這個方法告訴並行循環應該儘快中止執行,若是調用Stop時迭代100正在被處理,那麼循環沒法保證處理完全部小於100的迭代

下面貼代碼

    class Program
    {
        /*  coder:釋迦苦僧*/
        static void Main(string[] args)
        {
            
            List<Product> productList = GetProcuctList_500();
            Thread.Sleep(3000);
            Parallel.For(0, productList.Count, (i, loopState) =>
            {
                if (i < 100)
                {
                    Console.WriteLine("採用Stop index:{0}", i);
                }
                else
                {
                    /* 知足條件後 儘快中止執行,沒法保證小於100的索引數據所有輸出*/
                    loopState.Stop();
                    return;
                }
            });
     
            Thread.Sleep(3000);
            Parallel.For(0, productList.Count, (i, loopState) =>
            {
                if (i < 100)
                {
                    Console.WriteLine("採用Break index:{0}", i);
                }
                else
                {
                    /* 知足條件後 儘快中止執行,保證小於100的索引數據所有輸出*/
                    loopState.Break();
                    return;
                }
            });

            Thread.Sleep(3000);
            Parallel.ForEach(productList, (model, loopState) =>
            {
                if (model.SellPrice < 10)
                {
                    Console.WriteLine("採用Stop index:{0}", model.SellPrice);
                }
                else
                {
                    /* 知足條件後 儘快中止執行,沒法保證知足條件的數據所有輸出*/
                    loopState.Stop();
                    return;
                }
            });
            Thread.Sleep(3000);
            Parallel.ForEach(productList, (model, loopState) =>
            {
                if (model.SellPrice < 10)
                {
                    Console.WriteLine("採用Break index:{0}", model.SellPrice);
                }
                else
                {
                    /* 知足條件後 儘快中止執行,保證知足條件的數據所有輸出*/
                    loopState.Break();
                    return;
                }
            });

            Console.ReadLine();
        }
        private static List<Product> GetProcuctList_500()
        {
            List<Product> result = new List<Product>();
            for (int index = 1; index < 500; index++)
            {
                Product model = new Product();
                model.Category = "Category" + index;
                model.Name = "Name" + index;
                model.SellPrice = index;
                result.Add(model);
            }
            return result;
        }
    }
View Code

由圖中能夠看出Break能夠保證輸出知足全部條件的數據,而Stop則沒法保證。

 

關於 Parallel 類提供的 Parallel.InvokeParallel.For,Parallel.ForEach 的簡介入門到這,若有錯誤歡迎指正

 

做者:釋迦苦僧 出處:http://www.cnblogs.com/woxpp/p/3925094.html本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。

相關文章
相關標籤/搜索