繁体   English   中英

如何处理任务并行库中的目录文件?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM