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 系统。即使是一百个线程,也需要等待硬盘驱动器。所以我实际上希望并行化会因为开销而减慢整个操作。
有趣的是三重版本速度最快,虽然它读取目录的频率更高,但这可能是文件系统缓存造成的。因此,如果您 运行 在一个过程中直接一个接一个地直接测试所有三个,那么您的测试无论如何都不是正确的。
众所周知,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 系统。即使是一百个线程,也需要等待硬盘驱动器。所以我实际上希望并行化会因为开销而减慢整个操作。
有趣的是三重版本速度最快,虽然它读取目录的频率更高,但这可能是文件系统缓存造成的。因此,如果您 运行 在一个过程中直接一个接一个地直接测试所有三个,那么您的测试无论如何都不是正确的。