Diretory.GetFiles() 使用 Paralell.Foreach() 时的性能

Diretory.GetFiles() Performance when using Paralell.Foreach()

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

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

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

这是结果。

我不明白为什么使用一个 Parallel 比使用两个更快... 我完全不明白的是为什么他们发现的文件数量不同?!

长话短说这是我的代码:

Caller

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();
    }

Searching:

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 的数量。

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

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

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

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

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

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