【问题标题】:Diretory.GetFiles() Performance when using Paralell.Foreach()Directory.GetFiles() 使用 Parallel.Foreach() 时的性能
【发布时间】:2016-08-30 19:59:44
【问题描述】:

众所周知,Directory.GetFiles() 不是很快。 我试图尽快找到一些文件。 我遇到了一些奇怪的结果。

我开始使用Parallel.ForEach 并在我的C:\-Drive 上迭代所有Directorys

我实现了 3 个方法并显示了结果。它们在我用来深入目录的 Parallels 数量上有所不同。

这是结果。

我不明白为什么使用单个 Parallel 比使用两个更快... 我根本不明白为什么他们找到的文件数量不同?!

长话短说,这是我的代码:

来电者

private void Start(object sender, EventArgs e)
    {
        new Thread(() =>
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<FileInfo> files = HighPerformanceFileGettter.GetFilesInDirectory_DoubleParallel(@"C:\", "*.txt", SearchOption.AllDirectories);
            watch.Stop();
            MessageBox.Show($"Found [{files.Count}] files in [{watch.Elapsed.TotalMilliseconds}ms] => [{watch.Elapsed.TotalSeconds}]s", "Double Parallel");

        }).Start();
        new Thread(() =>
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<FileInfo> files = HighPerformanceFileGettter.GetFilesInDirectory_SingleParallell(@"C:\", "*.txt", SearchOption.AllDirectories);
            watch.Stop();
            MessageBox.Show($"Found [{files.Count}] files in [{watch.Elapsed.TotalMilliseconds}ms] => [{watch.Elapsed.TotalSeconds}]s", "Single Parallel");

        }).Start();
        new Thread(() =>
        {
            Stopwatch watch = new Stopwatch();
            watch.Start();
            List<FileInfo> files = HighPerformanceFileGettter.GetFilesInDirectory_TripleParallel(@"C:\", "*.txt", SearchOption.AllDirectories);
            watch.Stop();
            MessageBox.Show($"Found [{files.Count}] files in [{watch.Elapsed.TotalMilliseconds}ms] => [{watch.Elapsed.TotalSeconds}]s", "Tripe Parallel");

        }).Start();
    }

搜索:

public static List<FileInfo> GetFilesInDirectory_TripleParallel(string rootDirectory, string pattern, System.IO.SearchOption option)
    {
        List<FileInfo> resultFiles = new List<FileInfo>();

        //Suchen:
        DirectoryInfo root = new DirectoryInfo(rootDirectory);
        if (root.Exists)
        {
            //Performance:
            Parallel.ForEach(root.GetDirectories(), (dir) =>
            {
                try
                {
                    Parallel.ForEach(dir.GetDirectories(), (dir_1) =>
                    {
                        try
                        {
                            Parallel.ForEach(dir_1.GetDirectories(), (dir_2) =>
                            {
                                try
                                {
                                    resultFiles.AddRange(dir_2.GetFiles(pattern, option));
                                }
                                catch (Exception) { }
                            }); 
                        }
                        catch (Exception) { }
                    });
                }
                catch (Exception) { }
            });
            return resultFiles;
        }
        Debug.Fail($"Root [{root.FullName}] does not exist");
        return null;
    }

注意:我刚刚发布了三种方法中的一种,但你大喊看看有什么不同。它只是我使用的 Paralell.Foreach'es 的计数。

有没有人知道在性能方面最好的术语是什么以及为什么文件数不同?

【问题讨论】:

  • 如果您可以在返回结果时一次使用一个结果,那么Directory.EnumerateFiles 可能会有所帮助。至于不同的文件数,你检查过重复吗?
  • 就速度而言,磁盘 I/O 是主要的限制因素。您可以拥有任意数量的并行进程,但磁盘的寻道速度只能如此之快。
  • @AndrewMorton 即使有重复,不是所有三个函数都应该找到它们吗?
  • List 不是线程安全的。这应该是导致不同结果的原因。尝试使用线程安全集合。
  • 使用线程从磁盘驱动器读取是一个非常非常糟糕的主意。您只有一个驱动器,它确实喜欢让多个线程满意。磁盘寻道是迄今为止使用驱动器所能做的最昂贵的事情。特别危险,因为它不能很好地重复,第二次运行程序时,您将从内存而不是磁盘读取。警示故事是available here

标签: c# performance getfiles


【解决方案1】:

文件计数不同的原因是SearchOption.AllDirectories。在您的单个并行版本中,如果您阅读C:\,您将获得所有子目录中的所有文件。在您的三重版本中,您将获得

  • C:下方所有子目录中的所有文件`
  • 加上 `C:\dir1´ (-> 重复) 下所有子目录中的所有文件
  • 加上C:\dir1\dir2(-> 新副本) 下所有子目录中的所有文件

所以C:\ 中的所有文件都添加一次,C:\dir1 中的所有文件添加两次,C:\dir1\dir2 中的所有文件添加三次。

对于测量的时间:如果您从一个单个硬盘驱动器读取数据,并行化将无济于事。这里导致延迟的是 I/O 系统。甚至一百个线程仍然需要等待硬盘驱动器。所以我实际上预计并行化会因为开销而减慢整个操作。

有趣的是,三重版本虽然读取目录的频率更高,但速度最快,但这可能是文件系统缓存造成的。因此,如果您在一个进程中一个接一个地直接运行所有三个测试,那么无论如何您的测试并不是真正正确的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-26
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多