閱讀目錄:
創(chuàng)新互聯(lián)公司成立與2013年,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元博白做網(wǎng)站,已為上家服務(wù),為博白各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:028-869222201.開(kāi)篇介紹
2.NET并行計(jì)算基本介紹
3.并行循環(huán)使用模式
3.1并行For循環(huán)
3.2并行ForEach循環(huán)
3.3并行LINQ(PLINQ)
最近這幾天在搗鼓并行計(jì)算,發(fā)現(xiàn)還是有很多值得分享的意義,因?yàn)槲覀儸F(xiàn)在很多人對(duì)它的理解還是有點(diǎn)不準(zhǔn)確,包括我自己也是這么覺(jué)得,所以整理一些文章分享給在使用.NET并行計(jì)算的朋友和將要使用.NET并行計(jì)算的朋友;
NET并行編程推出已經(jīng)有一段時(shí)間了,在一些項(xiàng)目代碼里也時(shí)不時(shí)會(huì)看見(jiàn)一些眼熟的并行計(jì)算代碼,作為熱愛(ài)技術(shù)的我們?cè)跄芤暥灰?jiàn)呢,于是搗鼓了一番跟自己的理解恰恰相反,看似一段能提高處理速度的并行代碼為能起效果,跟直接使用手動(dòng)創(chuàng)建的后臺(tái)線程處理差不多,這不太符合我們對(duì).NET并行的強(qiáng)大技術(shù)的理解,所以自己搞了點(diǎn)資料看看,實(shí)踐了一下,發(fā)現(xiàn)在使用.NET并行技術(shù)的時(shí)候需要注意一些細(xì)節(jié),這些細(xì)節(jié)看代碼是看不出來(lái)的,所以我們看到別人這么用我們就模仿這么用,我們需要自己去驗(yàn)證一下到底能提高多少處理速度和它的優(yōu)勢(shì)在哪里;要不然效率上不去反而還低下,查看代碼也不能很好的斷定哪里出了問(wèn)題,所以還是需要系統(tǒng)的學(xué)習(xí)總結(jié)才行;
現(xiàn)在的系統(tǒng)已經(jīng)不在是以前桌面程序了,也不是簡(jiǎn)單的WEB應(yīng)用系統(tǒng),而是大型的互聯(lián)網(wǎng)社區(qū)、電子商務(wù)等大型系統(tǒng),具有高并發(fā),大數(shù)據(jù)、SOA這些相關(guān)特性的復(fù)雜體系的綜合性開(kāi)放平臺(tái);.NET作為市場(chǎng)占有率這么高的開(kāi)發(fā)技術(shù),有了一個(gè)很強(qiáng)大的并行處理技術(shù),目的就是為了能在高并發(fā)的情況下提高處理效率,提高了單個(gè)并發(fā)的處理效率也就提高了總體的系統(tǒng)的吞吐量和并發(fā)數(shù)量,在單位時(shí)間內(nèi)處理的數(shù)據(jù)量將提高不是一個(gè)系數(shù)兩個(gè)系數(shù);一個(gè)處理我們提高了兩倍到三倍的時(shí)間,那么在并發(fā)1000萬(wàn)的頂峰時(shí)時(shí)不時(shí)很客觀;
既然是.NET并行計(jì)算,那么我們首先要弄清楚什么叫并行計(jì)算,與我們以前手動(dòng)創(chuàng)建多線程的并行計(jì)算有何不同,好處在哪里;我們先來(lái)了解一下什么是并行計(jì)算,其實(shí)簡(jiǎn)單形容就是將一個(gè)大的任務(wù)分解成多個(gè)小任務(wù),然后讓這些小任務(wù)同時(shí)的進(jìn)行處理,當(dāng)然純屬自己個(gè)人理解,當(dāng)然不是很全面,但是我們使用者來(lái)說(shuō)足夠了;
在以前單個(gè)CPU的情況下只能靠提高CPU的時(shí)鐘頻率,但是畢竟是有極限的,所以現(xiàn)在基本上是多核CPU,個(gè)人筆記本都已經(jīng)基本上是4核了,服務(wù)器的話都快上20了;在這樣一個(gè)有利的計(jì)算環(huán)境下,我們的程序在處理一個(gè)大的任務(wù)時(shí)為了提高處理速度需要手動(dòng)的將它分解然后創(chuàng)建Thread來(lái)處理,在.NET中我們一般都會(huì)自己創(chuàng)建Thread來(lái)處理單個(gè)子任務(wù),這大家都不陌生,但是我們面臨的問(wèn)題就是不能很好的把握創(chuàng)建Thread的個(gè)數(shù)和一些參數(shù)的控制,畢竟.NET并行也是基于以前的Thread來(lái)寫(xiě)的,如何在多線程之間控制參數(shù),如何互斥的執(zhí)行的線程順序等等問(wèn)題,導(dǎo)致我們不能很好的使用Thread,所以這個(gè)時(shí)候.NET并行框架為我們提供了一個(gè)很好的并行開(kāi)發(fā)平臺(tái),畢竟大環(huán)境就是多核時(shí)代;
下面我們將接觸.NET并行計(jì)算中的第一個(gè)使用模式,有很多并行計(jì)算場(chǎng)景,歸結(jié)起來(lái)是一系列使用模式;
并行循環(huán)模式就是將一個(gè)大的循環(huán)任務(wù)分解成多個(gè)同時(shí)并行執(zhí)行的小循環(huán),這個(gè)模式很實(shí)用;我們大部分處理程序的邏輯都是在循環(huán)和判斷之間,并行循環(huán)模式可以適當(dāng)?shù)母纳莆覀冊(cè)诓僮鞔罅垦h(huán)邏輯的效率;
我們看一個(gè)簡(jiǎn)單的例子,看到底提升了多少CPU利用率和執(zhí)行時(shí)間;
using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Diagnostics; namespace ConsoleApplication1.Data { public class DataOperation { private static Listorders = new List (); static DataOperation() { for (int i = 0; i < 9000000; i++) { orders.Add(new Order() { Oid = Guid.NewGuid().ToString(), OName = "OrderName_" + i.ToString() }); } } public void Operation() { Console.WriteLine("Please write start keys:"); Console.ReadLine(); Stopwatch watch = new Stopwatch(); watch.Start(); orders.ForEach(order => { order.IsSubmit = true; int count = 0; for (int i = 0; i < 2000; i++) { count++; } }); watch.Stop(); Console.WriteLine(watch.ElapsedMilliseconds); } public void TaskOperation() { Console.WriteLine("Please write start keys:"); Console.ReadLine(); Stopwatch watch = new Stopwatch(); watch.Start(); Parallel.ForEach(orders, order => { order.IsSubmit = true; int count = 0; for (int i = 0; i < 2000; i++) { count++; } }); watch.Stop(); Console.WriteLine(watch.ElapsedMilliseconds); } } }
這里的代碼其實(shí)很簡(jiǎn)單,在靜態(tài)構(gòu)造函數(shù)中我初始化了九百萬(wàn)條測(cè)試數(shù)據(jù),其實(shí)就是Order類(lèi)型的實(shí)例,這在我們實(shí)際應(yīng)用中也很常見(jiàn),只不過(guò)不是一次性的讀取這么多數(shù)據(jù)而已,但是處理的方式基本上差不多的;然后有兩個(gè)方法,一個(gè)是Operation,一個(gè)是TaskOperation,前者順序執(zhí)行,后者并行執(zhí)行;
在循環(huán)的內(nèi)部我加上了一個(gè)2000的簡(jiǎn)單空循環(huán)邏輯,為什么要這么做后面會(huì)解釋介紹(小循環(huán)并行模式不會(huì)提升性能反而會(huì)降低性能);這里是為了讓模擬場(chǎng)景更真實(shí)一點(diǎn);
我們來(lái)看一下測(cè)試相關(guān)的數(shù)據(jù):i5、4核測(cè)試環(huán)境,執(zhí)行時(shí)間為42449毫秒,CPU使用率為25%左右,4核中只使用了1和3的,而其他的都屬于一般處理狀態(tài);
圖1:
我們?cè)賮?lái)看一下使用并行計(jì)算后的相關(guān)數(shù)據(jù):i5、4核測(cè)試環(huán)境,執(zhí)行時(shí)間為19927毫秒,CPU利用率為100%,4核中全部到達(dá)頂峰;
圖2:
這一個(gè)簡(jiǎn)單的測(cè)試?yán)?,?dāng)然我只測(cè)試了兩三組數(shù)據(jù),基本上并行計(jì)算的速度要快于單線程的處理速度的2.1倍以上,當(dāng)然還有其他因素在里面這里就不仔細(xì)分析了,起到拋磚引玉的作用;
在使用for循環(huán)的時(shí)候有相應(yīng)的Parallel方式使用for循環(huán),我們直接看一下示例代碼,還是以上面的測(cè)試數(shù)據(jù)為例;
Parallel.For(0, orders.Count, index => { // });
第一個(gè)參數(shù)是索引的開(kāi)始,第二個(gè)參數(shù)是循環(huán)總數(shù),第三個(gè)是執(zhí)行體,參數(shù)是索引值;使用起來(lái)其實(shí)很簡(jiǎn)單的;
同樣ForEach也是很簡(jiǎn)單的,還是使用上面的測(cè)試數(shù)據(jù)為例;
Parallel.ForEach(orders, order => { order.IsSubmit = true; int count = 0; for (int i = 0; i < 2000; i++) { count++; } });
在Parallel類(lèi)中有ForEach方法,第一個(gè)參數(shù)是迭代集合,第二個(gè)是每次迭代的item;
其實(shí)Parallel為我們封裝了一個(gè)簡(jiǎn)單的調(diào)用入口,其實(shí)是依附于后臺(tái)的Task框架的,因?yàn)槲覀兂S玫木褪茄h(huán)比較多,畢竟循環(huán)是任務(wù)的入口調(diào)用,所以我們使用并行循環(huán)的時(shí)候還是很方便的;
首先PLINQ是只針對(duì)Linq to Object的,所以不要誤以為它也可以使用于Linq to Provider,當(dāng)然自己可以適當(dāng)?shù)姆庋b;現(xiàn)在LINQ的使用率已經(jīng)很高了,我們?cè)谧鰧?duì)象相關(guān)的操作時(shí)基本上都在使用LINQ,很方便,特別是Select、Where非常的常用,所以.NET并行循環(huán)也在LINQ上進(jìn)行了一個(gè)封裝,讓我們使用LINQ的時(shí)候很簡(jiǎn)單的使用并行特性;
LINQ核心原理的文章:http://www.cnblogs.com/wangiqngpei557/category/421145.html
根據(jù)LINQ的相關(guān)原理,知道LINQ是一堆擴(kuò)展方法的鏈?zhǔn)秸{(diào)用,PLINQ就是擴(kuò)展方法的集合,位于System.Linq.ParallelEnumerable靜態(tài)類(lèi)中,擴(kuò)展于ParallelQuery
System.Linq.ParallelQuery
using System.Collections; using System.Collections.Generic; namespace System.Linq { // 摘要: // 表示并行序列。 // // 類(lèi)型參數(shù): // TSource: // 源序列中的元素的類(lèi)型。 public class ParallelQuery: ParallelQuery, IEnumerable , IEnumerable { // 摘要: // 返回循環(huán)訪問(wèn)序列的枚舉數(shù)。 // // 返回結(jié)果: // 循環(huán)訪問(wèn)序列的枚舉數(shù)。 public virtual IEnumerator GetEnumerator(); } }
System.Linq.ParallelEnumerable類(lèi):
// 摘要: // 提供一組用于查詢實(shí)現(xiàn) ParallelQuery{TSource} 的對(duì)象的方法。 這是 System.Linq.Enumerable 的并行等效項(xiàng)。 public static class ParallelEnumerable
我們?cè)谟玫臅r(shí)候只需要將它原本的類(lèi)型轉(zhuǎn)換成ParallelQuery
var items = from item in orders.AsParallel() where item.OName.Contains("1") select item;
Linq 的擴(kuò)展性真的很方便,可以隨意的封裝任何跟查詢相關(guān)的接口;
作者:王清培
出處:http://wangqingpei557.blog.51cto.com/
本文版權(quán)歸作者和51CTO共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。