簡體   English   中英

PLINQ與TPL的性能

[英]Performances of PLINQ vs TPL

我有一些數據庫操作要執行,我嘗試使用PLINQ

someCollection.AsParallel()
              .WithCancellation(token)
              .ForAll(element => ExecuteDbOperation(element))

而且我發現與以下內容相比,它的速度相當慢:

var tasks = someCollection.Select(element =>
                                    Task.Run(() => ExecuteDbOperation(element), token))
                          .ToList()

await Task.WhenAll(tasks)

我更喜歡PLINQ語法,但是我不得不使用第二個版本進行演奏。

有人可以解釋一下演出的巨大差異嗎?

如果您說多於10000個元素,那我相信,最好使用PLINQ,因為它不會為集合的每個元素創建任務,因為它在其中使用了Partitioner。 每個任務創建內部都有一些開銷數據初始化。 分區程序只會創建為當前可用內核優化的盡可能多的任務,因此它將重新使用此任務以及新數據進行處理。 您可以在此處了解更多信息: http : //blogs.msdn.com/b/pfxteam/archive/2009/05/28/9648672.aspx

我認為這是由於創建的線程數所致。

在第一個示例中,該數字將大致等於計算機的內核數。 相比之下,第二個示例將創建與someCollection具有元素一樣多的線程。 對於IO操作,通常效率更高。

Microsoft指南“ Patterns_of_Parallel_Programming_CSharp”建議IO操作創建比默認更多的線程(第33頁):

var addrs = new[] { addr1, addr2, ..., addrN };
var pings = from addr in addrs.AsParallel().WithDegreeOfParallelism(16)
select new Ping().Send(addr);

PLINQ和Parallel.ForEach()都主要用於處理受CPU約束的工作負載,這就是為什么它們在IO約束工作中表現不佳的原因。 對於某些特定的IO綁定工作,有一個最佳的並行度,但它並不取決於CPU內核的數量,而PLINQ和Parallel.ForEach()中的Parallel.ForEach()度卻取決於CPU內核的數量,或大或小。

具體來說,PLINQ的工作方式是使用固定數量的Task ,默認情況下根據您計算機上CPU內核的數量。 這對於一系列的PLINQ方法來說很有效。 但似乎這個數字小於您工作的理想並行度。

另一方面, Parallel.ForEach()代表確定要運行多少TaskThreadPool 而且,只要其線程被阻塞, ThreadPool慢慢添加它們。 結果是,隨着時間的流逝, Parallel.ForEach()可能會更接近理想的並行度。

正確的解決方案是通過測量,然后使用它來找出適合您的工作的並行度。

理想情況下,您將使代碼異步,然后使用某種方法來限制async代碼的並行度

既然您說還不能做到這一點,我認為一個不錯的解決方案可能是避免ThreadPool並在專用線程上運行您的工作(可以通過將Task.Factory.StartNew()TaskCreationOptions.LongRunning一起使用來創建線程) 。

如果您可以堅持使用ThreadPool ,那么另一個解決方案是使用PLINQ ForAll() ,還可以調用WithDegreeOfParallelism()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM