平行運算 (一):Parallel.For、Parallel.Foreach 用法及技巧
.NET Framework 4.0 增進了許多許多的功能,其中最令人興奮之一就是在平行運算(多執行緒)應用,將語法簡化的異常簡單,
對於平行運算的運作方式以及原理,可以參閱黃忠成老師的文章,可以有非常大的收穫,
這邊分享一下,實際運用Parallel.For、Parallel.Foreach的應用及一些技巧。
首先來我們來產生測試資料
//產生測試資料
List<string> testData = new List<string>();
//產生亂數字串
for (int i = 0; i < 100000; i++)
{
testData.Add(Rand.RndChars(2, 10));
}
其中 Rand.RndChars 是自己寫的產生亂數字串Method
現在做一個實驗,我要取得測試資料中包含a 或 包含 abc的字串,
分別利用 Foreach 、 Parallel.For 、 Parallel.Foreach 方式來比較執行的時間
Foreach
//紀錄結果用
List<string> resultData = new List<string>();
//找出 testData 中包含a 或 包含 abc的字串
foreach (var item in testData)
{
if (item.Contains("a") || item.Contains("abc"))
{
resultData.Add(item);
}
}
這段語法很簡單,取出 testData中 符合條件的資料,存入 resultData。
Parallel.For
//紀錄結果用
List<string> resultData = new List<string>();
Parallel.For(0, testData.Count() - 1, (i, loopState) =>
{
string data = testData[i];
if (data.Contains("a") || data.Contains("abc"))
{
resultData.Add(data);
}
});
這邊說明一下 Parallel.For 的用法,
public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);
public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int, ParallelLoopState> body);
這是最常使用的重載,其中 fromInclusive 是起始元素索引、toExclusive 是結束元素索引,用法與 for 一樣,
其中 Action<int,ParalleLoopState> 表示要執行的delegate
重要!!
在執行 Parallel.For 的範例時,一定會碰到一個很詭異的狀況,
有時候執行會正常,有時候會跳出以下的錯誤訊息
這是因為 在 .Net 3.5 之前所提供的所有 Collections 都不是 thread-safe 的,必須使用.Net 4.0 , System.Collections.Concurrent Namespace 下的泛型
因此這邊我們改寫一下語法
//紀錄結果用
ConcurrentStack<string> resultData2 = new ConcurrentStack<string>();
Parallel.For(0, testData.Count() - 1, (i, loopState) =>
{
string data = testData[i];
if (data.Contains("a") || data.Contains("abc"))
{
resultData2.Push(data);
}
});
改用 .Net 4.0 下提供的 ConcurrentStack<T>,來儲存結果
Parallel.Foreach
//紀錄結果用
ConcurrentStack<string> resultData2 = new ConcurrentStack<string>();
Parallel.ForEach(testData, (item, loopState) =>
{
if (item.Contains("a") || item.Contains("abc"))
{
resultData2.Push(item);
}
});
public static ParallelLoopResult ForEach<TSource>( IEnumerable<TSource> source, Action<TSource, ParallelLoopState> body )
第一個參數 source 是使用資料來源,第二個參數 Action<TSource, ParallelLoopState> 是要執行的delegate
測試結果
寫完以上語法後,
來比較一下效能吧
分別執行了20次,數字單位為 ms。
foreach: | 19 | Parallel.For: | 8 | Parallel.ForEach: | 8 |
foreach: | 21 | Parallel.For: | 7 | Parallel.ForEach: | 7 |
foreach: | 20 | Parallel.For: | 7 | Parallel.ForEach: | 7 |
foreach: | 19 | Parallel.For: | 7 | Parallel.ForEach: | 6 |
foreach: | 20 | Parallel.For: | 7 | Parallel.ForEach: | 8 |
foreach: | 19 | Parallel.For: | 5 | Parallel.ForEach: | 8 |
foreach: | 20 | Parallel.For: | 9 | Parallel.ForEach: | 6 |
foreach: | 19 | Parallel.For: | 8 | Parallel.ForEach: | 7 |
foreach: | 19 | Parallel.For: | 8 | Parallel.ForEach: | 8 |
foreach: | 19 | Parallel.For: | 8 | Parallel.ForEach: | 7 |
foreach: | 17 | Parallel.For: | 6 | Parallel.ForEach: | 7 |
foreach: | 17 | Parallel.For: | 7 | Parallel.ForEach: | 4 |
foreach: | 18 | Parallel.For: | 6 | Parallel.ForEach: | 5 |
foreach: | 17 | Parallel.For: | 4 | Parallel.ForEach: | 5 |
foreach: | 18 | Parallel.For: | 5 | Parallel.ForEach: | 7 |
foreach: | 20 | Parallel.For: | 9 | Parallel.ForEach: | 6 |
foreach: | 19 | Parallel.For: | 8 | Parallel.ForEach: | 6 |
foreach: | 19 | Parallel.For: | 9 | Parallel.ForEach: | 5 |
foreach: | 19 | Parallel.For: | 7 | Parallel.ForEach: | 5 |
foreach: | 21 | Parallel.For: | 7 | Parallel.ForEach: | 7 |
平均時間
foreach:18.17 ms
Parallel.For:7.17 ms
Parallel.Foreach:6.33 ms
語法非常的簡單,非常PowerFul。
下一篇 再來比較 另一種寫法 PLINQ 的作法,以及使用Parallel.For、Parallel.Foreach的限制,以及如果真的非使用List<> 不想修改現有程式時,是否有其他方式來實作
希望對大家有幫助~~
參考資料
How to: Write a Simple Parallel.For Loop
How to: Write a Simple Parallel.ForEach Loop
Introducing ConcurrentStack < T >
System.Collections.Concurrent Namespace
The Parallel Programming Of .NET Framework 4.0(1) – Beginning
The Parallel Programming Of .NET Framework 4.0(2) - Task Library
The Parallel Programming Of .NET Framework 4.0(3) - Deep Into Task Library
The Parallel Programming Of .NET Framework 4.0(4) - Inside Out Of Task Library
The Parallel Programming Of .NET Framework 4.0(5) - Dive to Parallel Programming
- 如果您覺得這篇文章有幫助,請您幫忙推薦一下或按上方的"讚"給予支持,非常感激
- 歡迎轉載,但請註明出處
- 文章內容多是自己找資料學習到的心得,如有不詳盡或錯誤的地方,請多多指教,謝謝