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

标签 c# multithreading task-parallel-library file-processing

我有一个场景,我必须根据处理器内核并行处理多个文件(例如 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;
        }
    }

最佳答案

对于像您这样的问题,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() 以接收文件名,而不是获取所有文件路径并处理其 block 。

这种方法的优点是现在您的 CPU 不会超额或不足,而且负载也会均衡。


我自己没有运行代码,所以我的代码中可能存在一些语法错误。如果您遇到任何错误,请随时纠正错误。

关于c# - 如何处理任务并行库中的目录文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34099876/

相关文章:

node.js - 仅在 NodeJs 上构建网站,并且 Express 阻止通过 http 的请求

c# - C# 中的 Async Func - 正确的 async await 用法

java - 试图理解为什么线程会在 Eclipse 中被阻塞?

java.net.Socket > InputStream > BufferedReader.read(char[]) 阻塞线程

c# - 如何在 MVC4 中执行异步调用操作方法

multithreading - 如何在没有主线程等待的情况下从长时间运行的后台任务引发异常

c# - C# 中的反射生成 SQL?

c# - 将 C# 中的字符串(不是数字或日期)格式化为给定模式

c# - 窗体上的控件未在设计器中显示

c# - 填充 asp :FileUpload from code behind