[英]How to process directory files in Task parallel library?
我有一個方案,其中我必須基於處理器內核並行處理多個文件(例如30個)。 我必須根據處理器核心的數量將這些文件分配給單獨的任務。 我不知道如何對要處理的每個任務進行開始和結束限制。 例如,每個任務都知道必須處理多少個文件。
private void ProcessFiles(object e)
{
try
{
var diectoryPath = _Configurations.Descendants().SingleOrDefault(Pr => Pr.Name == "DirectoryPath").Value;
var FilePaths = Directory.EnumerateFiles(diectoryPath);
int numCores = System.Environment.ProcessorCount;
int NoOfTasks = FilePaths.Count() > numCores ? (FilePaths.Count()/ numCores) : FilePaths.Count();
for (int i = 0; i < NoOfTasks; i++)
{
Task.Factory.StartNew(
() =>
{
int startIndex = 0, endIndex = 0;
for (int Count = startIndex; Count < endIndex; Count++)
{
this.ProcessFile(FilePaths);
}
});
}
}
catch (Exception ex)
{
throw;
}
}
基於我對TPL的有限理解,我認為您的代碼可以這樣重寫:
private void ProcessFiles(object e)
{
try
{
var diectoryPath = _Configurations.Descendants().SingleOrDefault(Pr => Pr.Name == "DirectoryPath").Value;
var FilePaths = Directory.EnumerateFiles(diectoryPath);
Parallel.ForEach(FilePaths, path => this.ProcessFile(path));
}
catch (Exception ex)
{
throw;
}
}
問候
對於諸如您這樣的問題,C#中提供了並發數據結構。 您要使用BlockingCollection並將所有文件名存儲在其中。
您使用計算機上可用的內核數來計算任務數的想法不是很好。 為什么? 因為對於每個文件, ProcessFile()
可能不會花費相同的時間。 因此,最好將任務數量作為您擁有的核心數量來開始。 然后,讓每個任務從BlockingCollection逐個讀取文件名,然后處理該文件,直到BlockingCollection為空。
try
{
var directoryPath = _Configurations.Descendants().SingleOrDefault(Pr => Pr.Name == "DirectoryPath").Value;
var filePaths = CreateBlockingCollection(directoryPath);
//Start the same #tasks as the #cores (Assuming that #files > #cores)
int taskCount = System.Environment.ProcessorCount;
for (int i = 0; i < taskCount; i++)
{
Task.Factory.StartNew(
() =>
{
string fileName;
while (!filePaths.IsCompleted)
{
if (!filePaths.TryTake(out fileName)) continue;
this.ProcessFile(fileName);
}
});
}
}
並且CreateBlockingCollection()
將如下所示:
private BlockingCollection<string> CreateBlockingCollection(string path)
{
var allFiles = Directory.EnumerateFiles(path);
var filePaths = new BlockingCollection<string>(allFiles.Count);
foreach(var fileName in allFiles)
{
filePaths.Add(fileName);
}
filePaths.CompleteAdding();
return filePaths;
}
您將必須修改ProcessFile()
以立即接收文件名,而不是采用所有文件路徑並處理其塊。
這種方法的優勢在於,現在您的CPU不會超過訂閱量或訂閱量不足,並且負載也將平均分配。
我尚未親自運行代碼,因此代碼中可能存在一些語法錯誤。 如果遇到任何錯誤,請隨時糾正錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.