Parallel.ForEach實測
Parallel.ForEach()是.NET 4.0下才有的新功能,用法就像一般的foreach迴圈一樣好用,但重點是,其內的程式碼不再是”依順序”執行了。變成在多執行緒下”平行”執行。
用法就不在這邊多做介紹了,接下我用實際的程式碼來進行測試,我寫了二個版本的程式,第一版用傳統的foreach,第二版用Parallel.ForEach(),並比較其速度及CPU使用情況
在介紹程式碼之前,先看一下流程圖,我要做的任務如下:
以下程式碼為非平行處理的版本:
SearchEngine src = new SearchEngine();
foreach (var job in db.KeywordQueue.Take(1000).ToList())
{
List<string> listKey = src.parter.KeywordPartition(prdName);
foreach (var k in listKey)
{
db2.sp_ProductKeywordReleation_Create(job.TableName, job.ProductId, k);
}
db.KeywordQueue.DeleteOnSubmit(job);
}
db.SubmitChanges();
接下來是平行處理的版本:
Parallel.ForEach(db.KeywordQueue.Take(1000).ToList(), (job, loopState) =>
{
SearchEngine src = new SearchEngine();
List<string> listKey = src.parter.KeywordPartition(prdName);
SaverDbDataContext db2 = new SaverDbDataContext();
foreach (var k in listKey)
{
db2.sp_ProductKeywordReleation_Create(job.TableName, job.ProductId, k);
}
lock (db)
{
db.KeywordQueue.DeleteOnSubmit(job); }
});
db.SubmitChanges();
二段程式碼本上是一模一樣的。現在來比較其執行結果
執行速度 | 雙核CPU效能 | |
Parllel.ForEach |
||
foreach |
結論:
- 在執行速度上快了近0.3倍
- 雙核的CPU,二個CPU的執行效能都有大幅度的提升,充份使用了CPU的處理程式
特別注意:
在寫Parllel.ForEach裏面的程式碼時,要把裏面的程式碼當成在”執行緒”裏執行。因此對於靜態,或公用變數的存取要加入lock,例如範例程式碼中,對db進行lock後再執行DeleteOnSubmit()方法。
如果不lock此處的db物件,在執行n筆之後(隨機),會出現NullException的例外錯誤。
PARTII 效能再優化
先看一下修正後的程式碼,如下…
SearchEngine src = new SearchEngine();
Parallel.ForEach(db.KeywordQueue.Take(1000).ToList(), (job, loopState) =>
{
try
{
List<string> listKey = new List<string>();
//SearchEngine src = new SearchEngine();<--這裏拿掉了
src.parter.KeywordPartition(prdName, ref listKey);
SaverDbDataContext db2 = new SaverDbDataContext();
foreach (var k in listKey)
{
db2.sp_ProductKeywordReleation_Create(job.TableName, job.ProductId, k);
}
lock (db)
{
db.KeywordQueue.DeleteOnSubmit(job);
}
});
請注意看綠色mark掉的部份…
SearchEngine是一個dll,裏面主要是將傳進去的prdName進行斷字斷詞,原先的寫法是在迴圈裏面創建出來的,現在把它拉到最上面。並且修改了方法,讓listKey這個串列改用外部程式碼傳入。
(原先SearchEngine裏面有一個List Class Member,一但拉出來共用之後,這個負責收集回傳結果list 就會被所有的多緒程式一起塞入keyword造成混亂。因此將list 改成區域變數傳進去,讓每個執行緒裏的list指向不同的記憶體。)
修改後,效能提升了30毫秒~
結論:
若資料量不大,那麼有沒用平行處理其實是沒有太大差別的。但如果資料量一大,例如有100萬筆,每筆53毫秒,只要14.7小時就會處理完,而在原先的foreach情況下則需要29小時才會處理完。