2010-10-01 10 views
6

Ich verwende den folgenden Code, um eine Prüfsumme einer Datei zu erstellen, die einwandfrei funktioniert. Aber wenn ich einen Hash für eine große Datei erzeuge, sagen wir 2 GB, ist das ziemlich langsam. Wie kann ich die Leistung dieses Codes verbessern?Verbessern Sie die Leistung von 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(); 

Update:

System:

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

Tests:

Test1 = 59,895 Sekunden

Test2 = 59,94 Sekunden

+1

+1 nur für den Versuch, die Leistung des schwersten Bit zu verbessern, und nicht darauf, dass formatiert ist in relativ ineffizienter Weise gebaut :) –

+0

:) sollte das wahrscheinlich zu einem stringbuilder ändern? –

+0

Ah, jetzt redest du dich selbst aus dieser +1! Was jedoch lohnend sein kann, wenn Sie solche Hex-Strings oft genug erzeugen, ist eine Methode, die dies tut (ein guter Fall für eine Erweiterungsmethode). Da es dann möglicherweise irgendwo verwendet wird, wo die Leistung einen größeren Unterschied macht, wäre es sinnvoller, den StringBuilder (mit der entsprechenden Kapazität erstellt) oder Char-Array-Ansätze mit fester Größe zu verschieben. –

Antwort

3

Die erste Frage ist, wofür Sie diese Prüfsumme benötigen. Wenn Sie die kryptografischen Eigenschaften nicht benötigen, dann ist ein nicht kryptografischer Hash oder ein Hash, der weniger kryptographisch sicher ist (MD5 ist "gebrochen", verhindert nicht, dass es ein guter Hash ist und für einige Verwendungen immer noch stark genug) wahrscheinlich leistungsfähiger. Sie könnten Ihren eigenen Hash erstellen, indem Sie eine Teilmenge der Daten lesen (ich würde empfehlen, diese Teilmenge in 4096-Byte-Chunks der zugrunde liegenden Datei zu arbeiten, da dies der von SHA1Managed verwendeten Puffergröße entspricht und ein schnelleres Chunk-Lesen ermöglicht Sie würden, wenn Sie alle X Bytes für einen Wert von X sagen würden).

Bearbeiten: Ein upvote erinnert mich an diese Antwort, hat mich auch daran erinnert, dass ich seit SpookilySharp schreibt, die leistungsstarke 32-, 64- und 128-Bit-Hashes, die nicht kryptografisch, aber gut für die Bereitstellung von Prüfsummen gegen Fehler bietet , Speicher usw. (Dies wiederum hat mich daran erinnert, dass ich es aktualisieren sollte, um .NET Core zu unterstützen).

Natürlich, wenn Sie möchten, dass der SHA-1 der Datei mit etwas anderem interagiert, stecken Sie fest.

Ich würde mit verschiedenen Puffergrößen experimentieren, da eine Erhöhung der Größe des Filestream-Puffers die Geschwindigkeit auf Kosten von zusätzlichem Speicher erhöhen kann. Ich würde ein ganzzahliges Vielfaches von 4096 empfehlen (4096 ist übrigens die Standardeinstellung), da SHA1Managed jeweils 4096 Stücke gleichzeitig anfordert, und auf diese Weise gibt es keinen Fall, in dem FileStream weniger zurückgibt als gewünscht (erlaubt aber manchmal) suboptimal) oder erstellt mehr als eine Kopie gleichzeitig.

+0

+1 für die erste Sequenz. Manchmal lösen wir das falsche Problem überhaupt. –

+0

Danke. Entschieden, mit MD5 zu gehen, da ich nur die Integrität der Dateien nach der Übertragung prüfte und die zusätzliche Sicherheit von SHA-1 nicht benötigte. Nur aus Neugier. Ich fand Intels neue Implementierung von SHA-1 mit SSE3-Anweisungen. http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/ Fragen Sie sich nur, ob und wie dies in verwaltetem Code verwendet werden kann? –

1

Nun, ist es IO-gebunden oder CPU-gebunden? Wenn es CPU-gebunden ist, können wir nicht viel dagegen tun.

Es ist möglich, dass die FileStream mit unterschiedlichen Parametern zu öffnen dem Dateisystem erlauben würde, mehr Pufferung oder annehmen zu tun, dass Sie die Datei sequentiell lesen werden - aber ich bezweifle, dass sehr viel helfen. (Es wird sicherlich nicht viel tun, wenn es CPU-gebunden ist.)

Wie langsam ist "ziemlich langsam" überhaupt? Verglichen mit etwa dem Kopieren der Datei?

Wenn Sie viel Arbeitsspeicher haben (z. B. 4 GB oder mehr), wie lange dauert es, die Datei ein zweites Mal zu hashen, wenn sie sich im Dateisystem-Cache befindet?

+0

Ich habe einige Geschwindigkeitstests durchgeführt. Überprüfen Sie mein Update. Auch die CPU-Auslastung liegt nur bei etwa 30%. –

+1

@Bruce: 30% insgesamt? Aus wie vielen Kernen? Wenn es sich um eine Multi-Core-CPU, aber einen single-threaded Hashing-Algorithmus handelt, könnte es immer noch CPU-gebunden sein. Sehen Sie auf der Registerkarte Leistung des Task-Managers nach, ob eine CPU für die gesamte Zeit gebunden ist :) –

+0

Nein, alle 4 Kerne liegen durchschnittlich bei etwa 5 - 6%. 2 Kerne machen ein bisschen Arbeit, aber nicht annähernd gekoppelt. Definitiv IO-gebunden, oder? –

1

Zuerst haben Sie "ziemlich langsam" gemessen? Von this site hat SHA-1 ungefähr die halbe Geschwindigkeit von MD5 mit ungefähr 100 MB/s (abhängig von der CPU), so dass 2 GB ungefähr 20 Sekunden zum Hash benötigen würden. Wenn Sie eine langsame Festplatte verwenden, ist dies möglicherweise Ihr echter Flaschenhals, da 30 bis 70 MB/s nicht ungewöhnlich sind.

Um die Dinge zu beschleunigen, können Sie einfach nicht die gesamte Datei, sondern die erste X KB oder darstellbare Teile davon (die Teile, die höchstwahrscheinlich unterscheiden werden). Wenn Ihre Dateien nicht zu ähnlich sind, sollte dies keine Duplikate verursachen.

1

Erstens: SHA-1 Datei Hashing sollte I/O-gebunden auf nicht-alten CPUs sein - und I5 sicherlich nicht als alt gelten. Natürlich hängt es von der Implementierung von SHA-1 ab, aber ich bezweifle, dass SHA1Managed über-langsam ist.

Als nächstes ist 60sec für 2GB Daten ~ 34MB/s - das ist langsam für Harddisk liest; Selbst eine 2,5 "-Laptop-Festplatte kann schneller lesen. Wenn man davon ausgeht, dass die Festplatte intern ist (kein USB2/was auch immer oder Netzwerkengpass), und es gibt nicht viele andere Festplatten-I/O-Aktivitäten, würde ich überrascht sein, weniger als 60 MB zu sehen/s von einem modernen Laufwerk lesen.

Meine Vermutung wäre, dass ComputeHash() intern einen kleinen Puffer verwendet. Versuchen Sie manuell Lese/Hashing, so können Sie einen größeren Puffer (64kb oder noch größer) zu erhöhen Durchsatz angeben. Sie auch Asynchron-Verarbeitung bewegen konnte so scheiben lesen und Compute überlappt werden kann.

-1

Sie können diese Logik für das erhalten SHA-1-Wert verwenden. ich es in Java verwendet wurde.

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

    } 
0

Weder ist die beste Wahl für große Eingabezeichenfolgen SHA1Managed, noch ist Byte.ToString ("X2") der schnellste Weg, um den Byte-Array in eine Zeichenfolge zu konvertieren.

Ich habe gerade einen Artikel mit detaillierten Benchmarks zu diesem Thema abgeschlossen. Es vergleicht SHA1Managed, SHA1CryptoServiceProvider, SHA1Cng und berücksichtigt auch SHA1.Create() auf Eingabezeichenfolgen mit unterschiedlicher Länge.

Im zweiten Teil werden 5 verschiedene Methoden gezeigt, um das Byte-Array in String zu konvertieren, wobei Byte.ToString ("X2") am schlechtesten ist.

Meine größte Eingabe war nur 10.000 Zeichen, also sollten Sie meine Benchmarks auf Ihrer 2 GB-Datei ausführen. Wäre ziemlich interessant, wenn/wie das die Zahlen ändert.

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

jedoch für die Dateiintegritätsprüfungen sind Sie besser dran mit MD5, wie Sie bereits geschrieben haben.

Verwandte Themen