为什么C#中的CRC32实现如此之慢?

rav*_*ven 4 .net c# crc32

我正在使用以下函数来计算VS2008,.NET 3.5项目中文件的CRC32:

public UInt32 ComputeHash(System.IO.Stream stream)
{
    unchecked
    {
        const int BUFFER_SIZE = 1024;

        UInt32 crc32Result = 0xFFFFFFFF;
        byte[] buffer = new byte[BUFFER_SIZE];
        int count = stream.Read(buffer, 0, BUFFER_SIZE);

        while (count > 0)
        {
            for (int i = 0; i < count; i++)
            {
                crc32Result = ((crc32Result) >> 8) ^ _crc32Table[(buffer[i]) ^ (crc32Result) & _LOOKUP_TABLE_MAX_INDEX];
            }
            count = stream.Read(buffer, 0, BUFFER_SIZE);
        }

        return ~crc32Result;
    }
}
Run Code Online (Sandbox Code Playgroud)

为简洁起见,我遗漏了构建查找表(_crc32Table)的函数.该表是一个UInt32数组,是在实例化类时构建的,包含256个值(256也是_LOOKUP_TABLE_MAX_INDEX + 1的值).

我已经运行了一些基准测试,将它与MD5CryptoServiceProvider和SHA1CryptoServiceProvider ComputeHash函数进行比较,它们的速度要快得多.MD5功能的速度提高了两倍,SHA1哈希的速度提高了约35%.我被告知CRC32很快,但那不是我所看到的.

我错误地假设了吗?这是预期的还是这个算法有缺陷?

Kar*_*arl 6

您正在将代码与内置函数进行比较,并询问它们为何更快.您需要做的是找到内置函数的源代码.他们是如何工作的?看看有什么不同.

Betcha内置函数调用本机库并且不必在托管内存框架内运行就作弊.

  • @raven,不一定.请记住,这样的内置功能经过多年设计,并在发货前进行了大量优化.就像Eric Lippert在他的评论中建议的那样,描述你的代码. (3认同)

Che*_*eso 0

也许:您在观察 CRC 吞吐量时是否计算了查找表的计算?通常,查找表计算一次并缓存。如果不缓存它,那么每次计算 CRC 时都会计算它。另外,如果您只测量一个 CRC,那么您可能已将表计算成本包含在 CRC 计算成本中。最好测量每个哈希的多次迭代。


附录:当我测量时,当使用 /debug+ 和 /optimize- 编译应用程序时,将 CRC32 与 MD5 哈希进行比较,我发现系数为 2.6 倍。使用 /debug- 和 /optimize+,我看到了 1.6 倍的系数。当我更改编译标志时,绝对 MD5 性能没有变化。在没有调试的情况下,CRC 仍然较慢,但已经接近得多。

  • 当然可以,但是您是否为每个哈希重新计算表?是静态表还是实例表。您是否计算哈希的多次迭代并平均响应时间?或者只是一个。如果它是一个实例变量,并且您为每个计算的 CRC32 创建一个 Crc32 类的新实例,那么您每次都会支付初始化成本。如果您只测量一个哈希值,那么您需要支付初始成本。不? (2认同)