为什么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 > 8) ^ _crc32Table[(buffer[i]) ^ (crc32Result) & _LOOKUP_TABLE_MAX_INDEX]; } count = stream.Read(buffer, 0, BUFFER_SIZE); } return ~crc32Result; } }
为简洁起见,我遗漏了构建查找表(_crc32Table)的函数。 该表是一个UInt32数组,是在实例化类时构建的,包含256个值(256也是_LOOKUP_TABLE_MAX_INDEX + 1的值)。
我已经运行了一些基准测试,将它与MD5CryptoServiceProvider和SHA1CryptoServiceProvider ComputeHash函数进行比较,它们的速度要快得多。 MD5function的速度提高了两倍,SHA1哈希的速度提高了约35%。 我被告知CRC32很快,但那不是我所看到的。
我在我的假设中弄错了吗? 这是预期的还是这个算法有缺陷?
您正在将代码与内置函数进行比较,并询问它们为何更快。 您需要做的是找到内置函数的源代码。 他们是如何工作的? 看看有什么不同。
Betcha内置函数调用本机库,并且不必在托管内存框架内运行就作弊。
分析可能有助于确定IO调用(读取)与CRC计算所花费的时间。 代码通常是IO绑定的。 但是,作为在C#中实现了相当快的CRCfunction的人,我可以给出一些指示,说明为什么它比MD5慢。
如果实现切片为N,则将所有查找表打包到一个大表中,以便可以通过相同的指针访问它们。 您也可以使用相同的表进行4切片和8切片。 另请注意,典型的N切片实现会假定特定的机器字节序,因此您可能需要为big-endian机器提供单独的版本,您可以使用BitConverter.IsLittleEndian进行检查。
我不太熟悉在执行此代码时自动执行的优化,但如果分析不适合您,则有几个选项。
我可以建议尝试不安全的代码,并使用指针运算缓冲区[i]和_crc32Table查找,以防它尚未被优化。
我可以看到你遇到性能问题的另一个地方是Stream.Read调用。 您是否尝试过不同的BUFFER_SIZE值?
如果没有自动优化,使用更大的字节缓冲区并可能进行一些手动循环展开也可以帮助您。
也许:你在计算CRC吞吐量的时候计算查找表吗? 通常,查找表计算一次并缓存。 如果不缓存它,则每次计算CRC时都会计算它。 此外,如果您只测量一个CRC,那么您可能已将表计算成本包括在CRC计算成本中。 最好测量每个哈希的多次迭代。
附录 :当我测量时,我看到了2.6倍的因子,比较你的CRC32和MD5哈希值,当应用程序是用/ debug +和/ optimize-编译的时候。 使用/ debug-和/ optimize +,我看到了1.6倍的因子。 当我更改编译标志时,绝对MD5性能没有变化。 没有调试,CRC仍然较慢,但它更接近。
上述就是C#学习教程:为什么C#中的CRC32实现如此之慢?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/955842.html