簡體   English   中英

並行性能

[英]Parallel.ForEach performance

我正在使用Parallel.ForEach提取一堆壓縮文件,並將它們復制到另一台計算機上的共享文件夾中,然后在該文件夾中開始BULK INSERT過程。 這一切都很好,但是我注意到,一旦出現一些大文件,就不會啟動新任務。 我認為這是因為某些文件比其他文件花費的時間更長,TPL開始按比例縮小,並停止創建新的任務。 我已經將MaxDegreeOfParallelism設置為一個合理的數字(8)。 當我查看CPU活動時,我可以看到,大多數情況下SQL Server計算機低於30%,而在執行單個BULK INSERT任務時則更少。 我認為它可以做更多的工作。 我可以以某種方式強制TPL創建更多同時處理的任務嗎?

原因很可能是默認情況下Parallel.ForEach處理項目的方式。 如果在數組或實現IList上使用它(這樣就可以使用總長度和索引器),它將分批拆分整個工作負載。 然后,單獨的線程將處理每個批次。 這意味着如果批次具有不同的“大小”(按大小,我是指處理它們的時間)-“小”批次將更快地完成。

例如,讓我們看下面的代碼:

var delays = Enumerable.Repeat(100, 24).Concat(Enumerable.Repeat(2000, 4)).ToArray();
Parallel.ForEach(delays, new ParallelOptions() {MaxDegreeOfParallelism = 4}, d =>
{
    Thread.Sleep(d);
    Console.WriteLine("Done with " + d);
});

如果運行它,您將看到所有“ 100”(快速)項目都被快速並行處理。 但是,所有“ 2000”(慢)項目最終都將一一處理,而無需任何並行處理。 這是因為所有“慢”項目都在同一批次中。 工作負載分為4個批次( MaxDegreeOfParallelism = 4 ),並且前3個僅包含快速項目。 他們完成得很快。 最后一批具有所有慢速項目,因此專用於此批處理的線程將逐個處理它們。

您可以通過確保項目均勻分配(以使“慢”項目在源集合中不全部在一起)來“修復”您的情況,例如使用自定義分區程序:

var delays = Enumerable.Repeat(100, 24).Concat(Enumerable.Repeat(2000, 4)).ToArray();
var partitioner = Partitioner.Create(delays, EnumerablePartitionerOptions.NoBuffering);
Parallel.ForEach(partitioner, new ParallelOptions {MaxDegreeOfParallelism = 4}, d =>
{
    Thread.Sleep(d);
    Console.WriteLine("Done with " + d);
});

NoBuffering可以確保一次提取一項,從而避免了該問題。

也可以使用其他方式來並行化工作(例如SemaphoreSlimBlockingCollection )。

暫無
暫無

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

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