提高SHA-1 ComputeHash的性能

时间:2010-10-01 08:56:29

标签: c# .net performance

我正在使用以下代码对文件进行校验和,该文件工作正常。但是当我为一个大文件生成哈希值时,比如2 GB,它很慢。如何提高此代码的性能?

fs = new FileStream(txtFile.Text, FileMode.Open);
        formatted = string.Empty;
        using (SHA1Managed sha1 = new SHA1Managed())
        {
            byte[] hash = sha1.ComputeHash(fs);

            foreach (byte b in hash)
            {
                formatted += b.ToString("X2");
            }
        }
        fs.Close();

更新

系统:

操作系统:Win 7 64位,CPU:I5 750,内存:4GB,硬盘:7200rpm

试验:

Test1 = 59.895秒

测试2 = 59.94秒

6 个答案:

答案 0 :(得分:3)

第一个问题是你需要这个校验和。如果您不需要加密属性,那么非加密哈希或加密安全性较低的哈希(MD5被“破坏”并不会阻止它成为一个好的哈希,也不能用于某些用途)可能更高效。您可以通过读取数据的子集来创建自己的哈希(我建议使这个子集在4096byte的基础文件块中工作,因为这将匹配SHA1Managed使用的缓冲区大小以及允许更快的块读取如果你确实说过每个X字节的某个X值,你会这么做。

编辑:一个提醒我这个答案的upvote,也提醒我,我写了SpookilySharp,它提供了高性能的32位,64位和128位哈希,这些哈希不是加密的,但很适合提供校验和防止错误,存储等(这反过来提醒我,我应该更新它以支持.NET Core)。

当然,如果您希望文件的SHA-1与其他内容互操作,那么您就会陷入困境。

我会尝试不同的缓冲区大小,因为增加文件流缓冲区的大小会增加速度,但需要额外的内存。我建议4096的整数倍(4096是默认值,顺便提一下),因为SHA1Managed一次会要求4096个块,这样就不会有任何FileStream返回少于最多请求的情况(允许但有时候)次优的)或一次做多个副本。

答案 1 :(得分:1)

嗯,是IO绑定还是CPU限制?如果它受CPU限制,我们就无法做很多事情。

使用不同参数打开FileStream可能会允许文件系统进行更多缓冲,或者假设您要按顺序读取文件 - 但我怀疑这会帮助非常

反正“缓慢”有多慢?与复制文件相比?

如果你有大量内存(例如4GB或更多),那么第二次散列文件需要多长时间,那么它可能在文件系统缓存中?

答案 2 :(得分:1)

首先,你测得“很慢”吗?从this site开始,SHA-1的速度大约是MD5的一半,大约100 MB / s(取决于CPU),因此2 GB需要大约20秒的时间来进行散列。此外,请注意,如果您使用的是慢速硬盘,这可能是您真正的瓶颈,因为30-70 MB / s并不罕见。

为了加快速度,你可能不会散列整个文件,而是第一个X KB或其可表示的部分(最有可能不同的部分)。如果您的文件不太相似,则不应导致重复。

答案 3 :(得分:1)

首先:SHA-1文件散列应该在非古老的CPU上进行I / O绑定 - 而I5当然不具备古老的资格。当然这取决于SHA-1的实现,但我怀疑SHA1Managed是非常慢的。

接下来,2GB数据的60秒是〜34MB / s - 硬盘读取速度慢;即使是2.5英寸的笔记本电脑磁盘也能读得更快。假设硬盘是内置的(没有USB2 /无论什么或网络瓶颈),并且没有其他磁盘I / O活动,我会惊讶地看到不到60MB / s从现代驱动器中读取。

我的猜测将是ComputeHash()内部使用小缓冲区。尝试手动读取/散列,因此您可以指定更大的缓冲区(64kb甚至更大)以提高吞吐量。您还可以转到异步处理,以便磁盘读取和计算可以重叠。

答案 4 :(得分:0)

SHA1Managed既不是大输入字符串的最佳选择,也不是Byte.ToString(“X2”)将字节数组转换为字符串的最快方法。

我刚刚完成了一篇关于该主题的详细基准测试的文章。它比较SHA1Managed,SHA1CryptoServiceProvider,SHA1Cng,并在不同长度的输入字符串上考虑SHA1.Create()。

在第二部分中,它显示了将字节数组转换为字符串的5种不同方法,其中Byte.ToString(“X2”)是最差的。

我最大的输入只有10,000个字符,因此您可能希望在2 GB文件上运行我的基准测试。如果/如何改变数字会非常有趣。

http://wintermute79.wordpress.com/2014/10/10/c-sha-1-benchmark/

但是,对于文件完整性检查,最好使用MD5,就像您已经写过的那样。

答案 5 :(得分:-1)

您可以使用此逻辑获取SHA-1值。 我在java中使用它。

public class sha1Calculate {

    public static void main(String[] args)throws Exception
    {
         File file = new File("D:\\Android Links.txt");
        String outputTxt= "";
        String hashcode = null;

        try {

            FileInputStream input = new FileInputStream(file);

            ByteArrayOutputStream output = new ByteArrayOutputStream ();
            byte [] buffer = new byte [65536];
            int l;

            while ((l = input.read (buffer)) > 0)
                output.write (buffer, 0, l);

            input.close ();
            output.close ();

            byte [] data = output.toByteArray ();


                MessageDigest digest = MessageDigest.getInstance( "SHA-1" ); 

            byte[] bytes = data;

            digest.update(bytes, 0, bytes.length);
            bytes = digest.digest();

            StringBuilder sb = new StringBuilder();

            for( byte b : bytes )
            {
                sb.append( String.format("%02X", b) );
            }

                System.out.println("Digest(in hex format):: " + sb.toString());


        }catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    }