【问题标题】:Performance issues while creating file checksums创建文件校验和时的性能问题
【发布时间】:2017-05-23 12:52:44
【问题描述】:

我正在编写一个控制台应用程序,它遍历二叉树并根据 md5 校验和搜索新的或更改的文件。 整个过程很快(大约 70.000 个文件需要 14 秒),但生成校验和大约需要 5 分钟,这太慢了......

对改进这个过程有什么建议吗?我的哈希函数如下:

private string getMD5(string filename)
        {
            using (var md5 = new MD5CryptoServiceProvider())
            {
                if (File.Exists(@filename))
                {
                    try
                    {
                        var buffer = md5.ComputeHash(File.ReadAllBytes(filename));
                        var sb = new StringBuilder();
                        for (var i = 0; i < buffer.Length; i++)
                        {
                            sb.Append(buffer[i].ToString("x2"));
                        }
                        return sb.ToString();
                    }
                    catch (Exception)
                    {
                        Program.logger.log("Error while creating checksum!", Program.logger.LOG_ERROR);
                        return "";
                    }
                }
                else
                {
                    return "";
                }
            }
        } 

【问题讨论】:

  • 您可以使用ComputeHash(Stream) 重载并传递文件流,而不是将文件内容读入内存。
  • @Lee 让我的代码运行得更慢了.. 但感谢您的意图

标签: c# md5 checksum


【解决方案1】:

好吧,接受的答案是无效的,因为当然,有一种方法可以提高您的代码性能。但是,它适用于其他一些想法)

除了磁盘 I/O 之外,这里的主要障碍是内存分配。这里有一些应该提高速度的想法:

  • 不要在内存中读取整个文件进行计算,它很慢,并且会通过LOH对象产生很大的内存压力。而是将文件作为流打开,并按块计算 Hash。
  • 原因,为什么使用ComputeHash流覆盖时会变慢,因为它内部使用非常小的缓冲区(4kb),所以选择适当的缓冲区大小(256kb或更大,通过实验找到最佳值)
  • 使用TransformBlockTransformFinalBlock 函数计算哈希值。您可以为 outputBuffer 参数传递 null。
  • 重复使用该缓冲区进行后续文件哈希计算,因此无需额外分配。
  • 此外,您还可以重复使用 MD5CryptoServiceProvider,但好处值得怀疑。
  • 最后,您可以应用异步模式从流中读取块,因此当您计算前一个块的部分哈希时,操作系统会同时从磁盘读取下一个块。当然,这样的代码更难编写,并且您至少需要两个缓冲区(也可以重复使用它们),但它会对速度产生很大影响。
  • 作为一个小改进,不检查文件是否存在。我相信,您的函数是从某个枚举中调用的,并且该文件同时被删除的可能性很小。

以上所有内容均适用于中型到大型文件。相反,如果您有很多非常小的文件,则可以通过并行处理文件来加快计算速度。实际上并行化也可以帮助处理大文件,但需要衡量。

最后,如果冲突不会给您带来太多困扰,您可以选择成本较低的哈希算法,例如 CRC。

【讨论】:

    【解决方案2】:

    为了创建哈希,您必须读取文件的每个最后一个字节。因此,此操作受磁盘限制,不受 CPU 限制,并且与文件大小成比例。多线程将无济于事。

    除非 FS 可以以某种方式为您计算和存储哈希,否则无法加快速度。您依赖于 FS 为您所做的工作来跟踪更改。

    通常检查“已更改文件”(如备份例程)的程序不会出于该原因计算哈希值。他们可能仍会计算并存储它以用于验证目的,但仅此而已。

    除非用户做了一些严重的(NTFS 驱动程序加载级别)破坏,文件大小的“最后更改”日期足以检测到更改。也许还可以检查存档位,但现在很少使用。

    对这类场景(列出文件并处理它们)的一个小改进是使用“Enumerate Files”而不是列出文件。但是在 14 秒的清单/5 分钟的处理中,不会有任何相关的效果。

    【讨论】:

      猜你喜欢
      • 2017-07-01
      • 2021-10-01
      • 1970-01-01
      • 2022-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-20
      • 2011-01-06
      相关资源
      最近更新 更多