程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 並行編程 之 PLINQ 基本使用

C# 並行編程 之 PLINQ 基本使用

編輯:C#入門知識

C# 並行編程 之 PLINQ 基本使用


PLINQ Summary

LINQ (LINQ) Language Integrated Query 可以方便的查詢並處理不同數據源的數據。PLINQ Parallel LINQ不光擁有LINQ的功能,還添加了並行操作的接口,以方便使用並提高效率。

 

一個簡單的例子

用一個簡單的例子足以說明PLINQ的使用。
簡單的說明:
第一部分:先在一個文檔中查詢包含字母 “a”的單詞首先使用 LINQ進行查詢10000次,然後使用PLINQ進行同樣的測試,看看效率有多少提高。 AsParallel() 是主要用到的接口。

第二部分:計算Short類型所有數字的和,同樣測試兩次使用LINQ和PLINQ。

第三部分:測試PLINQ的查找排序功能。使用的接口分別為AsOrdered()和orderby
AsOrdered:保持數據在數據源中的順序不變。
orderby:按用戶指定的順序進行排序,升序/降序

示例程序:

using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Linq;
using System.IO;

namespace Sample6_1_plink_basic
{
    class Program
    {
        static int SumDefault(int[] array)
        {
            return array.Sum();
        }

        static int SumAsParallel(int[] array)
        {
            return array.AsParallel().Sum();
        }

        static string[] words = { Day, Car, Land, Road, Sea, Mountain, River};

        static void Main(string[] args)
        {
            var customers = System.IO.File.ReadAllLines(@D:	estdirCSParallel_ProgramSample6-1 plink basic	arget.txt);
            int nCounter = 0;
            Console.WriteLine(============================================================);
            Console.WriteLine(TEST NORMAL LINQ);
            Console.WriteLine(============================================================);
            var swatchpn = Stopwatch.StartNew();

            for (int i = 0; i < 10000; i++)
            {
                var normalkeyLetters = from line in customers
                                       let keys = line.Split(' ')
                                       from key in keys
                                       where (key.Contains('a'))
                                       select key;

                var normalkeyList = normalkeyLetters.ToList();
                nCounter = normalkeyList.Count();
            }

            swatchpn.Stop();
            Console.WriteLine(Word with letter a = {0}, nCounter);
            Console.WriteLine(LINQ Use Time: {0}, swatchpn.Elapsed);

            Console.WriteLine(

);
            Console.WriteLine(============================================================);
            Console.WriteLine(TEST PARALLEL LINQ);
            Console.WriteLine(============================================================);
            nCounter = 0;
            var swatchp = Stopwatch.StartNew();

            for (int i = 0; i < 10000; i++)
            {

                var keyLetters = from line in customers.AsParallel()
                                 let keys = line.Split(' ')
                                 from key in keys.AsParallel()
                                 where (key.Contains('a'))
                                 select key;

                var keyList = keyLetters.ToList();
                nCounter = keyList.Count();
            }

            swatchp.Stop();
            Console.WriteLine(Word with letter a = {0}, nCounter);
            Console.WriteLine(PLINQ Use Time: {0}, swatchp.Elapsed);

            // Generate array.
            int[] array = Enumerable.Range(0, short.MaxValue).ToArray();
            const int m = 10000;
            var s1 = Stopwatch.StartNew();
            for (int i = 0; i < m; i++)
            {
                SumDefault(array);
            }
            s1.Stop();

            var s2 = Stopwatch.StartNew();
            for (int i = 0; i < m; i++)
            {
                SumAsParallel(array);
            }
            s2.Stop();
            Console.WriteLine(

);
            Console.WriteLine(============================================================);
            Console.WriteLine(CALCULATE SUMMARY TEST);
            Console.WriteLine(============================================================);
            Console.WriteLine(Default Summary:  + ((double)(s1.Elapsed.TotalMilliseconds * 1000000) / m).ToString(0.00 ns));
            Console.WriteLine(Parallel Summary:  + ((double)(s2.Elapsed.TotalMilliseconds * 1000000) /m).ToString(0.00 ns));


            Console.WriteLine(

);
            Console.WriteLine(============================================================);
            Console.WriteLine(Parallel ASOrder Test);
            Console.WriteLine(============================================================);
            var orderwords = from word in words.AsParallel().AsOrdered()
                             where (word.Contains('a'))
                             select word;

            var orderletterList = orderwords.ToList();
            for (int i = 0; i < orderletterList.Count; i++)
            {
                Console.WriteLine(orderletterList[i]);
            }


            Console.WriteLine(

);
            Console.WriteLine(============================================================);
            Console.WriteLine(Parallel OrderBy Test);
            Console.WriteLine(============================================================);
            var orderbywords = from word in words.AsParallel()
                             where (word.Contains('a'))
                             orderby word ascending
                             select word;

            var orderbyletterList = orderbywords.ToList();
            for (int i = 0; i < orderbyletterList.Count; i++)
            {
                Console.WriteLine(orderbyletterList[i]);
            }

            Console.ReadKey();
        }
    }
}

測試結果:
這裡寫圖片描述

測試其實運行過多次,關於單詞的測試LINQ的結果在32至34秒,PLINQ大概在16至19秒,大約有50%的提升。

關於PLINQ中的數據分區

PLINQ使用多個任務對同一個數據源進行處理,然後匯總,使得效率提高。但並行執行的任務應該處理數據的哪個部分,怎樣對數據進行合理的劃分,並且分配給任務是很重要的,它會嚴重的影響效率。但開發者並不太可能去真正的控制PLINQ去采用哪種分區方式,了解一下它的內部機理在優化程序性能時會有一定的幫助。

PLINQ中有四種數據的劃分方式:

范圍劃分:用於可索引的數據源,例如數組和列表。PLINQ會查找數據源的IList接口,如果找到了,它就會采取范圍據劃分方式,將數據分解為與可用的邏輯內核數目相等的分區。PLINQ可以確切的知道數據規模,而且可以直接訪問其中的任意元素。
數據塊劃分:適用於任何數據源,用於不可索引的數據,不同任務此時得到的是數據塊,塊的大小可能不一樣。
交錯式分區:這種方式對在數據源頂部對數據項進行處理的情況進行了優化。當查詢包括SkipWhile和TakeWhile時會采用這種方式。此時每個任務對應的是一小組數據(簡稱條紋)。任務通過簡單的計算可以判斷出數據對應的條紋,所以任務間並不需要同步。
散列分區:主要針對數據比較進行了優化。它在數據和任務間建立了通道,帶有相同散列碼的數據項會被發送到同一個任務中,這樣有可能的匹配便會在一個數據分區中,從而簡化了比較的過程,減少了不同任務間的數據共享。采用這種方式時分發數據時可能會有較大的開銷,但數據比較時效率會提高。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved