每次迭代复制文件时使用 EnumerateFiles() 与 GetFiles() 是否会造成性能损失?

问题描述 投票:0回答:1

当然还有其他方法可以做到这一点,但只是为了论证,如果我在下面的代码中将 EnumerateFiles() 替换为 GetFiles() ,使用 GetFiles() 似乎会提高性能,它> 1 秒。对于 10 个目录,每个目录包含 10 个文件,比 EnumerateFiles() 更快。

有人知道这是为什么吗?

这很有趣,因为我假设 EnumerateFiles() 由于延迟加载而更有效,而 GetFiles() 是旧式的处理方式。 微软只说 EnumerateFiles() 在处理大型集合时更有效,没有任何性能损失......

https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.enumeratedirectories?view=net-8.0

这是因为文件复制操作尝试在不同位置读取和写入磁盘时,仍然枚举文件系统条目吗?那么磁头必须来回切换吗?看来有什么要注意的!

后续问题:这如何通过网络共享进行?

using System;
using System.IO;    

// Copy all the files in source paths to target paths
foreach( string newPath in Directory.EnumerateFiles( masterRecordingsDirectory, "*.*", SearchOption.AllDirectories ) )                                      
{     
    File.Copy( newPath, newPath.Replace( masterRecordingsDirectory, currentRecordingsDirectory ) );    
}

编辑: 正如评论中的人们所指出的,这两种方法都在底层调用了InternalEnumeratePaths()。但重点是,Get 方法在返回之前首先转换为 List,而 Enumerate 开始生成路径,而其他方法仍在检索中。所以在我看来,问题仍然存在,哪种方法适合哪种情况? Microsoft 文档没有详细介绍这一点。

Edit2:我再次使用不同名称的文件/文件夹进行测试,以防止缓存丢弃结果。我仍然发现有利于 GetFiles()/GetDirectories() 的差异(尽管现在以毫秒为单位)。 还有更多的文件读取是针对 Enumerate(在 80 年代)而不是 GetFiles(在 50 年代),这似乎支持这些结果。 但请继续在上面打洞!

这是我的测试代码:

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()));
            }
        }
        // Copy all the files in source paths to target paths
        foreach (string newPath in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
            File.Copy(newPath, newPath.Replace(sourceDir, targetDir));

    }
}
c# .net file-io
1个回答
0
投票

因此,我按照 @Charlieface 的建议使用 BenchmarkDotNet 来获得更精确的测试结果,并且我必须承认 EnumerateFiles() 是明显的赢家,本地调用速度快了 10 倍以上。对于网络上的结果,差异似乎更大,但我无法进行良好的测试,因为它运行的时间太长,因此测试套件因错误而中途停止。

本地文件操作结果:

作业=MediumRun工具链=InProcessNoEmitToolchain IterationCount=15
启动次数=1 预热次数=10

方法 意思是 错误 标准偏差 中位数
列举 46.63 毫秒 8.663 毫秒 7.234 毫秒 43.00 毫秒
获取 607.26 毫秒 435.252 毫秒 407.135 毫秒 366.41 毫秒

免责声明:我关闭了所有其他窗口和进程,但可能仍然是测试不完美,Get 操作的 StdDev 相当高。虽然我运行了多次测试,但结果总是和上面类似。

据我所知,结论:使用 EnumerateFiles/Dirs 而不是 Get!

© www.soinside.com 2019 - 2024. All rights reserved.