【问题标题】:Optimizing Dictionary.EnumerateFiles over network通过网络优化 Dictionary.EnumerateFiles
【发布时间】:2014-11-15 02:43:07
【问题描述】:

我目前有一个扫描网络共享的程序。为此,它首先枚举共享上的所有文件和目录。这是一个非常缓慢的过程。我目前使用以下代码,取自本网站 2011 年的回答。

static class SafeWalk
    {
        public static IEnumerable<string> EnumerateFiles(string path, string searchPattern, SearchOption searchOpt)
        {
            try
            {
                var dirFiles = Enumerable.Empty<string>();
                if (searchOpt == SearchOption.AllDirectories)
                {
                    dirFiles = Directory.EnumerateDirectories(path)
                                        .SelectMany(x => EnumerateFiles(x, searchPattern, searchOpt));
                }
                return dirFiles.Concat(Directory.EnumerateFiles(path, searchPattern));
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine(ex.Message);
                return Enumerable.Empty<string>();
            }
        }
    }

问题在于程序中的所有其他内容都是多线程的并且针对速度进行了优化。这是唯一严重阻碍我的领域。枚举网络共享中的文件可能需要几分钟的时间。这是在 Intranet 上,并且我的机器和服务器之间有千兆位或更大的连接。

当我在运行时将网络路径临时映射到驱动器时​​,我确实加快了速度。我能做些什么来加快速度吗?查看资源监视器,它几乎没有使用任何 CPU、内存或网络带宽。

【问题讨论】:

  • 与其创建递归方法,不如为Directory.EnumerateFiles使用适当的重载不是更容易吗?
  • 如果您无权访问文件/目录,Directory.EnumerateFiles 会引发错误。如果这样做,它只会返回到目前为止发现的内容,可能是 70GB 中的 3MB。 :-(
  • 那么我想你唯一的选择是下面链接的快速目录枚举器。在 C# 中反复捕获异常和递归方法将比直接枚举慢...
  • 您对该网络共享拥有何种访问权限?你能在那个盒子上远程运行代码吗?或者它只是普通的普通网络共享,只有读取和写入文件的权限有限?
  • @VikasGupta 我无权在服务器上运行代码。我对共享中包含的大约 98% 的文件具有读/写访问权限。某些目录是禁止访问的,即使对我来说也是如此。

标签: c# .net multithreading optimization


【解决方案1】:

考虑使用 PInvoke 调用带有选项 FIND_FIRST_EX_LARGE_FETCHFindFirstFileExAccording to Raymond Chen this flag is made for your situation.

【讨论】:

  • 很遗憾,该值对 Windows 7 无效。
  • @Red_Shadow 在这种情况下,我建议您编写一个在远程计算机上运行并公开 API 以枚举目录的小应用程序。然后,您可以使用快速的本地枚举并通过网络以非闲聊的方式有效地流式传输结果。
  • 其实重读了msdn,我觉得是说windows 7及以上都支持,只是措辞有点别扭。此外,我根本无法在远程机器上执行任何代码。该工具旨在安装在扫描机器上,并能够扫描网络上的任何其他机器。
【解决方案2】:

您是否经常在高容量下使用相同的搜索参数搜索相同的路径?您可以使用缓存结果吗?如果是这样,我建议添加缓存机制。我们遇到了类似的事情,尽管我们并没有如此笼统和细化地公开它,我只是缓存了结果。或者,如果您对此不满意,是否可能是调用者的逻辑没有保存结果,而是循环多次调用 this?

【讨论】:

    【解决方案3】:

    Fast Directory Enumerator 适合你。

    为什么它更快?

    Directory.GetFiles 和 DirectoryInfo.GetFiles 或 Directory.EnumerateFile() 有许多缺点。最重要的是它们会丢弃信息,并且不能有效地让您同时检索有关多个文件的信息。

    在内部,Directory.GetFiles 被实现为 Win32 FindFirstFile/FindNextFile 函数的包装器。这些函数都返回有关 GetFiles() 方法在返回文件名时丢弃的每个枚举文件的信息。他们还使用一条网络消息检索有关多个文件的信息。

    FastDirectoryEnumerator 保存此信息并在 FileData 类中返回它。这大大减少了完成相同任务所需的网络往返次数。

    【讨论】:

    • 不,该项目早于 .NET 4.0 中添加的 EnumerateFiles/Directory() 方法。这解决了完全相同的问题。 OP 已经在使用它了。
    • 尝试使用这个库:它在初始测试中比我当前的解决方案慢了大约 5 倍。
    • 上次我使用 Reflector 查看 FindFirstFile 的信息并没有被丢弃。
    • 请不要引导人们使用它。 Directory.EnumerateFiles/Directory 方法已经在 .NET 中并且更好。
    猜你喜欢
    • 2017-04-12
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多