创建文件校验和时的性能问题

时间:2017-05-23 12:52:44

标签: c# md5 checksum

我正在编写一个控制台应用程序,它遍历二叉树并根据其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 "";
                }
            }
        } 

2 个答案:

答案 0 :(得分:2)

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

除磁盘I / O外,此处的主要停止是内存分配。这里有一些想要提高速度的想法:

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

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

最后,如果碰撞没有太多困扰你,你可以选择较便宜的哈希算法,例如CRC。

答案 1 :(得分:1)

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

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

通常用于检查&#34;更改文件的程序&#34; (就像备份例程一样)不计算Hashvalue就是出于这个原因。他们仍然可以计算和存储它以用于验证目的,但就是这样。

除非用户做了一些严重的(NTFS驱动程序加载级别)破坏,否则&#34;最后一次更改&#34;使用filesize的日期足以检测更改。也许还要检查存档位,但现在很少使用它。

对于这些场景(列出文件并处理它们)的微小改进是使用&#34; Enumerate Files&#34;而不是列出文件。但在14秒上市/ 5分钟处理将没有任何相关效果。