詳解c# PLINQ中的分區(qū)
最近因?yàn)楸容^忙,好久沒(méi)有寫(xiě)博客了,這篇主要給大家分享一下PLINQ中的分區(qū)。上一篇介紹了并行編程,這邊詳細(xì)介紹一下并行編程中的分區(qū)和自定義分區(qū)。
先做個(gè)假設(shè),假設(shè)我們有一個(gè)200Mb的文本文件需要讀取,怎么樣才能做到最優(yōu)的速度呢?對(duì),很顯然就是拆分,把文本文件拆分成很多個(gè)小文件,充分利用我們計(jì)算機(jī)中的多核cpu的優(yōu)勢(shì),讓每個(gè)cpu都充分的利用,達(dá)到效率的最大化。然而在PLINQ中也是,我們有一個(gè)數(shù)據(jù)源,如果想進(jìn)行最大的并行化操作,那么就需要把其拆分為可以多個(gè)線(xiàn)程同時(shí)訪問(wèn)的多個(gè)部分,這就是PLINQ中的分區(qū)。當(dāng)然,微軟已經(jīng)為我們想到了這一點(diǎn),知道他的用戶(hù)可能會(huì)有這個(gè)需求,所以就先說(shuō)一下微軟給我們提供的默認(rèn)的一個(gè)分區(qū)程序吧。
微軟提供的默認(rèn)的分區(qū)程序又叫做任務(wù)并行庫(kù)(TPL),其實(shí)就是當(dāng)你用PLINQ的ForEach的時(shí)候,默認(rèn)在其內(nèi)部就會(huì)給我們進(jìn)行分區(qū)。怎么樣,是不是很方便。不過(guò)有時(shí)候,你可能會(huì)需要自己來(lái)進(jìn)行拆分,那么就是另外一種跟高級(jí)一點(diǎn)的用法了,就是PLINQ的自定義分區(qū)。自定義分區(qū)有兩種,一種是按照范圍分區(qū),另一種是按照區(qū)塊分區(qū)。其中按照范圍分區(qū)在針對(duì)鏈表集合能夠提供非常好的性能,比如IList等,不過(guò)它也有一點(diǎn)缺點(diǎn)那就是如果一個(gè)線(xiàn)程提前完成,它將無(wú)法幫助其他線(xiàn)程完成它們的工作。按照區(qū)塊分區(qū)是當(dāng)我們不知道我們所要操作的集合的大小的時(shí)候,可以使用按照區(qū)塊分區(qū),在按區(qū)塊分區(qū)中,并行循環(huán)或查詢(xún)中的每個(gè)線(xiàn)程或任務(wù)都使用一個(gè)區(qū)塊中一定數(shù)量的源元素,對(duì)它們進(jìn)行處理,然后返回檢索其他元素。分區(qū)程序可確保分發(fā)所有元素,并且沒(méi)有重復(fù)項(xiàng)。區(qū)塊可為任意大小。
通常,只有當(dāng)委托的執(zhí)行時(shí)間為較短到中等程度,源具有大量的元素,并且每個(gè)分區(qū)的總工作量大致相等時(shí),按范圍分區(qū)的速度才會(huì)較快。因此,按區(qū)塊分區(qū)的速度在大多數(shù)情況下較快。對(duì)于元素?cái)?shù)量很少或委托執(zhí)行時(shí)間較長(zhǎng)的源,則按區(qū)塊分區(qū)和按范圍分區(qū)的性能大致相等。
那么我們?nèi)绾螌?shí)現(xiàn)動(dòng)態(tài)分區(qū)呢?下面有一個(gè)摘自MSDN的示例。
每次分區(qū)對(duì)枚舉器調(diào)用 MoveNext 時(shí),枚舉器都會(huì)提供包含一個(gè)列表元素的分區(qū)。對(duì)于 PLINQ 和 ForEach,分區(qū)是一個(gè) Task 實(shí)例。由于請(qǐng)求同時(shí)在多個(gè)線(xiàn)程上發(fā)生,因此對(duì)當(dāng)前索引的訪問(wèn)是同步的。
// // An orderable dynamic partitioner for lists // class OrderableListPartitioner<TSource> : OrderablePartitioner<TSource> { private readonly IList<TSource> m_input; public OrderableListPartitioner(IList<TSource> input) : base(true, false, true) { m_input = input; } // Must override to return true. public override bool SupportsDynamicPartitions { get { return true; } } public override IList<IEnumerator<KeyValuePair<long, TSource>>> GetOrderablePartitions(int partitionCount) { var dynamicPartitions = GetOrderableDynamicPartitions(); var partitions = new IEnumerator<KeyValuePair<long, TSource>>[partitionCount]; for (int i = 0; i < partitionCount; i++) { partitions[i] = dynamicPartitions.GetEnumerator(); } return partitions; } public override IEnumerable<KeyValuePair<long, TSource>> GetOrderableDynamicPartitions() { return new ListDynamicPartitions(m_input); } private class ListDynamicPartitions : IEnumerable<KeyValuePair<long, TSource>> { private IList<TSource> m_input; private int m_pos = 0; internal ListDynamicPartitions(IList<TSource> input) { m_input = input; } public IEnumerator<KeyValuePair<long, TSource>> GetEnumerator() { while (true) { // Each task gets the next item in the list. The index is // incremented in a thread-safe manner to avoid races. int elemIndex = Interlocked.Increment(ref m_pos) - 1; if (elemIndex >= m_input.Count) { yield break; } yield return new KeyValuePair<long, TSource>( elemIndex, m_input[elemIndex]); } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<KeyValuePair<long, TSource>>)this) .GetEnumerator(); } } } class ConsumerClass { static void Main() { var nums = Enumerable.Range(0, 10000).ToArray(); OrderableListPartitioner<int> partitioner = new OrderableListPartitioner<int>(nums); // Use with Parallel.ForEach Parallel.ForEach(partitioner, (i) => Console.WriteLine(i)); // Use with PLINQ var query = from num in partitioner.AsParallel() where num % 2 == 0 select num; foreach (var v in query) Console.WriteLine(v); } }
這是按區(qū)塊分區(qū)的示例,其中每個(gè)區(qū)塊都由一個(gè)元素組成。通過(guò)一次提供多個(gè)元素,您可以減少鎖爭(zhēng)用,并在理論上實(shí)現(xiàn)更快的性能。但是,有時(shí)較大的區(qū)塊可能需要額外的負(fù)載平衡邏輯才能使所有線(xiàn)程在工作完成之前保持忙碌。
以上就是詳解c# PLINQ中的分區(qū)的詳細(xì)內(nèi)容,更多關(guān)于c# PLINQ中的分區(qū)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于c#中枚舉類(lèi)型支持顯示中文的擴(kuò)展說(shuō)明
需求 : 枚舉類(lèi)型在界面顯示的時(shí)候可以顯示相應(yīng)的中文信息, 這樣界面對(duì)用戶(hù)友好 . 場(chǎng)景 : 在一些業(yè)務(wù)中涉及到審核功能的時(shí)候, 往往有這幾個(gè)狀態(tài)?。何此蛯?, 審核中 ,審核通過(guò), 駁回?。∵@個(gè)時(shí)候我們會(huì)定義一個(gè)枚舉類(lèi)型來(lái)描述?。?/div> 2013-03-03C#使用正則表達(dá)式隱藏手機(jī)號(hào)中間四位為*
這篇文章主要介紹了C#使用正則表達(dá)式隱藏手機(jī)號(hào)中間四位為*的相關(guān)資料,需要的朋友可以參考下2017-06-06C#程序中session值的保存方法以及轉(zhuǎn)為字符串的方法總結(jié)
這篇文章主要介紹了C#程序中session值的保存方法以及轉(zhuǎn)為字符串的方法總結(jié),經(jīng)常被用于ASP.NET網(wǎng)絡(luò)編程項(xiàng)目中,需要的朋友可以參考下2016-04-04c#的dataset離線(xiàn)數(shù)據(jù)集示例
這篇文章主要介紹了c#的dataset離線(xiàn)數(shù)據(jù)集示例,需要的朋友可以參考下2014-04-04C#使用HttpWebRequest與HttpWebResponse模擬用戶(hù)登錄
這篇文章主要為大家詳細(xì)介紹了C#使用HttpWebRequest與HttpWebResponse模擬用戶(hù)登錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04C#常用多線(xiàn)程(線(xiàn)程同步,事件觸發(fā),信號(hào)量,互斥鎖,共享內(nèi)存,消息隊(duì)列)
這篇文章主要介紹了C#常用多線(xiàn)程(線(xiàn)程同步,事件觸發(fā),信號(hào)量,互斥鎖,共享內(nèi)存,消息隊(duì)列),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-09-09淺談C# async await 死鎖問(wèn)題總結(jié)
這篇文章主要介紹了淺談C# async await 死鎖問(wèn)題總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10C#開(kāi)發(fā)Windows窗體應(yīng)用程序的簡(jiǎn)單操作步驟
這篇文章主要介紹了C#開(kāi)發(fā)Windows窗體應(yīng)用程序的簡(jiǎn)單操作步驟,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04c# 引用類(lèi)型與值類(lèi)型的區(qū)別詳解
本篇文章是對(duì)c#中引用類(lèi)型與值類(lèi)型的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05最新評(píng)論