2010-10-01 31 views
6

我正在使用下面的代碼來執行工作正常的文件的校驗和。但是當我爲一個大文件生成一個散列時,比如說2 GB,它就很慢。我怎樣才能提高這段代碼的性能?提高SHA-1 ComputeHash的性能

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(); 

更新:

系統:

OS:Win 7的64位,CPU:I5 750,RAM:4GB,HDD:7200rpm的

測試:

Test1 = 59.895秒

Test2 = 59.94秒

+1

+1只是爲了試圖改善最重的位的性能,而不是關心格式化是建立在一個相對低效的方式:) –

+0

:)應該可能改變到一個stringbuilder? –

+0

現在,你正在說出自己的+1!如果你經常產生這樣的十六進制字符串,有什麼可以值得的是有一個方法可以做到這一點(對於擴展方法來說是很好的例子)。隨着它可能被用於性能會更加真實的區域,那麼移動StringBuilder(以適當的容量創建)或固定大小的char數組方法會更有價值。 –

回答

3

第一個問題是你需要這個校驗和。如果你不需要加密屬性,那麼非加密散列或加密安全性較低的散列(MD5被「破解」並不妨礙它是一個好的散列,但對某些用途來說仍然足夠強大)是可能更具性能。你可以通過讀取一部分數據來創建你自己的哈希(我建議讓這個子集在底層文件的4096byte塊中工作,因爲這樣會匹配SHA1Managed使用的緩衝區大小,並且允許讀取更快的數據塊你會如果你確實說X的某個值的每個X字節)。

編輯:upvote提醒我這個答案,也提醒我,我寫了SpookilySharp它提供了高性能的32位,64位和128位散列,這些散列並不是密碼學的,但很適合提供校驗和來防止錯誤,存儲等(這反過來提醒我應該更新它來支持.NET Core)。

當然,如果您希望文件的SHA-1與其他東西進行互操作,您會被卡住。

我會嘗試不同的緩衝區大小,因爲增加文件流緩衝區的大小會增加速度,但需要增加額外的內存。我建議整個4096的倍數(4096是默認值,順便說一下),因爲SHA1Managed一次將要求4096個塊,這樣就不會有任何一個FileStream返回小於最大請求的情況(允許但有時次優)或一次做多個副本。

+0

第一個序列的+1。有時我們完全解決了錯誤的問題。 –

+0

謝謝。決定採用MD5,因爲我只在傳輸後檢查文件的完整性,並且不需要額外的SHA-1安全性。 只是出於好奇。我發現英特爾使用SSE3指令的新SHA-1實現。 http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/只是想知道如何以及如何在託管代碼中使用它? –

1

那麼,它是IO綁定還是CPU綁定?如果它受到CPU的限制,那麼我們可以做的並不多。

這有可能是使用不同的參數打開FileStream將允許文件系統做更多的緩衝或假設你要讀文件的順序 - 但我懷疑,這將有助於非常多。 (如果CPU限制,這肯定不會有太大的進步。)

反正「很慢」的速度有多慢?比如說,複製文件?

如果您有很多內存(例如4GB或更多),則需要多長時間對文件進行散列處理(可能位於文件系統緩存中)?

+0

我跑了一些速度測試。檢查我的更新。另外CPU使用率僅達到約30%。 –

+1

@布魯斯:總共30%?有多少核心?如果它是一個多核CPU但是是單線程哈希算法,它仍然可能受CPU限制。查看任務管理器的性能標籤,查看一個CPU是否與整個時間掛鉤:) –

+0

不,所有4個內核的平均值約爲5-6%。 2個核心做了一點工作,但沒有接近掛鉤。肯定IO綁定的權利? –

1

首先,你有沒有測量過「相當慢」?從this site開始,SHA-1的MD5速度約爲100MB/s(取決於CPU)的一半,所以2GB需要大約20秒的散列時間。另外請注意,如果您使用的是慢速硬盤,這可能是您真正的瓶頸,因爲30-70 MB/s並不罕見。爲了加快速度,您可能不會散列整個文件,而是第一個X KB或其可表示的部分(最有可能不同的部分)。如果你的文件不太相似,這不應該導致重複。

1

第一:SHA-1文件散列應該在非古代的CPU上綁定I/O,而I5當然不符合古代的要求。當然這取決於SHA-1的實現,但是我懷疑SHA1Managed是否超速。

接下來,2GB數據的60秒是〜34MB/s--硬盤讀取速度慢;即使2.5英寸筆記本電腦磁盤的讀取速度也比這更快,假設硬盤是內部的(沒有USB2 /任何或網絡瓶頸),並且沒有太多其他磁盤I/O活動,我很驚訝地看到少於60MB /從現代驅動器閱讀S。

猜測將是ComputeHash()使用一個小緩衝區內。嘗試手動讀/散列,所以你可以指定一個更大的緩存(64KB或更大),以提高產量。您也可以移動到異步處理,磁盤讀取和計算可以重疊。

-1

我在Java中使用它你可以使用這個邏輯讓SHA-1的值。 。

公共類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(); 
    } 

    } 
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因爲你已經寫了。