EnumerateFiles与GetFiles循环复制文件时的性能差异及原因探究
Directory.EnumerateFiles与GetFiles在文件复制场景下的性能差异
测试发现
在循环复制文件的场景中,将代码中的Directory.EnumerateFiles()替换为Directory.GetFiles()后,发现后者性能更优:在10个各包含10个文件的目录测试场景下,EnumerateFiles()比GetFiles()慢1秒以上。
预期反差与原因猜测
原本认为EnumerateFiles()凭借延迟加载(lazy loading)特性会更高效,微软官方仅说明其在处理大集合时表现更优,未提及存在性能损耗。推测性能差异的原因可能是:枚举文件系统条目与文件复制操作同时进行,导致磁盘磁头频繁切换,额外增加了IO开销。
底层实现差异补充
二者底层均调用InternalEnumeratePaths()方法,但存在关键区别:
GetFiles()/GetDirectories()会先将枚举结果转换为List后一次性返回EnumerateFiles()/EnumerateDirectories()则是边枚举边返回结果
经过排除缓存干扰的多次测试,仍能复现Get系列方法性能更优的结果,且Enumerate系列方法的文件读取次数更多。
待验证疑问
这种性能差异在网络共享目录场景下会如何表现?
测试代码
初始测试代码
using System; using System.IO; // 复制源路径下的所有文件到目标路径 foreach( string newPath in Directory.EnumerateFiles( masterRecordingsDirectory, "*.*", SearchOption.AllDirectories ) ) { File.Copy( newPath, newPath.Replace( masterRecordingsDirectory, currentRecordingsDirectory ) ); }
二次测试代码
using System; using System.IO; using System.Linq; internal class Program { static void Main(string[] args) { string baseDir = Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments), "Test2"); string sourceDir = Path.Combine(baseDir, "Source2"); string targetDir = Path.Combine(baseDir, "Target2"); Directory.CreateDirectory(baseDir); Directory.CreateDirectory(sourceDir); Directory.CreateDirectory(targetDir); for (int i = 1; i < 10; i++) { Directory.CreateDirectory(Path.Combine(sourceDir, "Blah2" + i.ToString())); } foreach (var dir in Directory.GetDirectories(sourceDir)) { for (int i = 1; i < 10; i++) { File.Create(Path.Combine(dir, "Blah2" + i.ToString())); } } // 复制源路径下的所有文件到目标路径 foreach (string newPath in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, newPath.Replace(sourceDir, targetDir)); } }
内容的提问来源于stack exchange,提问作者wecky
相关产品推荐
相关产品推荐

