上一篇《C#中多執行緒的那點事-Parallel》,我們講述了一種全新的資料並行處理方法Parallel,Parallel也是 TPL(Task Parallel Library)提供的一個類。其提供的Invoke可以非常方便的開啟並行任務;For,Foreach可以非常方便的對大量資料進行並行處理。
小明同學,昨天回家練習了Parallel的使用,不禁感嘆,C#真的是處處為開發者著想。當你覺得程式碼囉嗦複雜的時候,也許應該去查一查有沒有用C#更簡單的實現方法!
我告訴小明,聽了今天的課程,以前那些簡單方法,都是小兒科!
小明聽了我這話之後,兩眼放光,彷彿在說,那你還不開始。。。
基礎補充在正式開始之前,我們先簡單說一下C#中的擴充套件方法。這是一種可以給類和介面,動態新增擴充套件函式的機制。利用擴充套件方法,可以在不改變已有程式碼的前提下,擴充套件類和介面的功能。
如果已經瞭解了C#的擴充套件函式的同學,可以直接跳到下一節。
先看個簡單的例項:
// 集合擴充套件類public static class ListExt{ // 計算集合平均值 public static int Avg(this List<int> list) { int sum = 0; foreach (var l in list) { sum += l; } return sum / list.Count; }}
注意,以上的ListExt類,有3個特點:
ListExt是一個staitc類函式Avg是一個static函式Avg的引數list前面,添加了this關鍵字沒錯,以上3點,就是C#中的擴充套件函式的基本語法。這樣我們在不修改List這個類原有程式碼的情況下,給List<int>添加了一個Avg函式,來計算集合中全部資料的平均值。
我們這裡為了簡單起見,先不考慮模板和計算溢位。
另外,我們看到擴充套件函式,實質上還是一個靜態的函式,在擴充套件函式中,也只能訪問原來的類的公有成員。
那這個Avg函式如何使用呢:
class Program{ static void Main(string[] args) { Console.WriteLine("Hello LINQ World!"); var list = new List<int>(); for (int i = 0; i < 100; i++) { list.Add(i); } var avg = list.Avg(); Console.WriteLine($"Average: {avg}"); }}
可以看到,和使用List<int>的其他函式一模一樣。
其實擴充套件函式,就是利用靜態函式,包裝的一種語法糖,方便我們更直觀的使用。這種操作看似平淡無奇,但是在微軟的加持下,就發揮出了無窮的威力。請接著往下看。
LINQ集合,包括List,Dictionary,HashSet等,是我們日常程式設計中使用最廣泛的資料結構。而這些類本身,雖然是泛型的,支援各種資料的集合。但其本身提供的功能函式有限。
就比如前文的求平均值的功能,我們每次都要編寫一次迴圈,或者需要封裝輔助類。程式碼冗餘,使用不直觀。
微軟在程式語言方面,確實是處處為程式設計師著想,他們早就注意到了這個問題。也給出了他們的解決方案,就是LINQ。
LINQ是一組基於C#擴充套件函式實現的通用集合處理函式合集。其中包括了大多數對於集合的常規操作:
元素訪問函式,比如First,Last,ElementAt,Single,FirstOrDefault統計相關函式,比如Average,Min,Max,Sum,Aggregate(聚合,很好用)邏輯判斷函式,比如All,Any,Contains,SequenceEqual(判斷集合相等)集合操作函式,比如Select,Where,Append,OrderBy,Concat,Distinct,Except,Intersect,Join,Reverse,Union分組變換函式,比如ToDictionary,ToLookup,ToHashSet,GroupBy騷操作函式,比如Cast,OfType,Empty,Prepend,Range,Repeat,ThenBy,Zip以上是常用的集合相關函式,還有一些不常用的函式,就不一一列舉了。總之有一點,有了這些函式,我們操作集合會方便太多,效率大增。絕對是乾貨。LINQ就是傳說中的那種用過之後就回不去的API合集。
這些特性,在其他程式語言看來一定是這樣的:
這TM絕對是來搗亂的
我看了一眼小明,躍躍欲試的樣子,像極了當年的我!
PLINQ今天的內容有點多,我讓大家休息了一會,消化消化。沒過一會,小明來找我說道:
老師,LINQ中的操作是並行的嗎?
不得不說,小明學習多執行緒是有點著魔了,不過我非常喜歡他這個狀態。
LINQ的操作,是序列的。不過微軟當然也想到了小明的這個需求,於是他們又搞了一個PLINQ。
PLINQ就是並行的LINQ的意思。其API基本和LINQ相同,微軟對PLINQ的介紹,也說PLINQ是LINQ的並行替代實現。
來看一個簡單的PLINQ的例項程式:
static void Main(string[] args){ Console.WriteLine("Hello PLINQ World!"); var list = new List<int>(); for (int i = 0; i < 10; i++) { list.Add(i); } var plist = list.AsParallel(); var avg = plist.Average(); Console.WriteLine($"PLINQ Average: {avg}"); plist.ForAll(l => { Console.WriteLine($"value: {l}, " + $"tid: {Thread.CurrentThread.ManagedThreadId}"); });}
程式中透過PLINQ的AsParallel函式,將普通的集合,轉換為一個並行的集合。程式輸出如下:
PLINQ並行遍歷集合
從結果中可以看出,PLINQ的並行遍歷集合,和ThreadPool及Parallel執行的機制相同。但是PLINQ的功能要強大得多。
看到這裡,相信你一定已經被C#的魅力所吸引。這也是C#在程式語言中,可以一直排在前5的原因之一。
TOIOBE排行2020-10
佈置作業練習PLINQ的使用。
聰明的小明
踩坑記錄暫無
下期預告下面是給同學們準備的乾貨,正在陸續發貨中哦:
await/async