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會查找數據源的IList接口,如果找到了,它就會采取范圍據劃分方式,將數據分解為與可用的邏輯內核數目相等的分區。PLINQ可以確切的知道數據規模,而且可以直接訪問其中的任意元素。