2010-10-01 14 views
6

Sto usando il seguente codice per eseguire un checksum di un file che funziona correttamente. Ma quando genero un hash per un file di grandi dimensioni, diciamo 2 GB, è piuttosto lento. Come posso migliorare le prestazioni di questo codice?Migliorare le prestazioni di 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(); 

Aggiornamento:

Sistema:

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

Test:

Test1 = 59,895 secondi

Test2 = 59,94 secondi

+1

+1 solo per cercare di migliorare le prestazioni del bit più pesante, e non preoccuparsi che il formato sia costruito in un modo relativamente inefficiente :) –

+0

:) dovrebbe probabilmente cambiarlo in un costruttore di stringhe? –

+0

Ah, ora ti stai parlando di quel +1! Ciò che può essere utile se si producono tali stringhe esadecimali spesso è avere un metodo che faccia questo (buon caso per un metodo di estensione). Essendo quindi potenzialmente utilizzato da qualche parte dove le prestazioni faranno la differenza più reale, sarebbe più utile spostare il StringBuilder (creato alla capacità appropriata) o gli approcci di array di char a dimensione fissa. –

risposta

3

La prima domanda è ciò per cui è necessario questo checksum. Se non hai bisogno delle proprietà crittografiche, allora un hash non crittografico, o un hash che è meno crittograficamente sicuro (MD5 "rotto" non impedisce che sia un buon hash, né ancora abbastanza forte per alcuni usi) è probabilmente più performante. Potresti creare il tuo hash leggendo un sottoinsieme di dati (ti consiglio di fare in modo che questo sottoinsieme funzioni in 4096 byte di file sottostante, poiché questo corrisponderebbe alla dimensione del buffer usata da SHA1Managed oltre a consentire una lettura più veloce di lo faresti se dicessi ogni X byte per qualche valore di X).

Edit: un upvote ricordandomi di questa risposta, ha anche mi ha ricordato che ho da quando scrissi SpookilySharp che fornisce alte prestazioni a 32, a 64 ea 128 bit hash crittografico che non sono, ma buona per la fornitura di checksum contro gli errori , archiviazione, ecc. (Questo a sua volta mi ha ricordato che dovrei aggiornarlo per supportare .NET Core).

Ovviamente, se si desidera che l'SHA-1 del file interagisca con qualcos'altro, si è bloccati.

Vorrei sperimentare diverse dimensioni del buffer, poiché l'aumento delle dimensioni del buffer del filestream può aumentare la velocità a scapito della memoria aggiuntiva. Consiglierei un intero multiplo di 4096 (4096 è l'impostazione predefinita, incidentalmente) poiché SHA1Managed chiederà 4096 blocchi alla volta, e in questo modo non ci saranno casi in cui FileStream restituisce meno del più richiesto (consentito ma a volte non ottimale) o fa più di una copia alla volta.

+0

+1 per la prima sequenza. A volte stiamo risolvendo del tutto il problema sbagliato. –

+0

Grazie. Deciso di andare con MD5 poiché stavo controllando l'integrità dei file solo dopo la trasmissione e non ho richiesto la sicurezza extra di SHA-1. Solo per curiosità. Ho trovato la nuova implementazione di Intel di SHA-1 usando le istruzioni SSE3. http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/ Mi chiedo solo se e come questo può essere utilizzato nel codice gestito? –

1

Bene, è legato all'IO o alla CPU? Se è legato alla CPU, non c'è molto che possiamo fare al riguardo.

E 'possibile che l'apertura del FileStream con parametri diversi permetterebbe il file system di fare di più buffering o dare per scontato che si sta andando a leggere il file in sequenza - ma dubito che vi aiuterà molto molto. (Certamente non farà molto se è legato alla CPU.)

Quanto è lento "abbastanza lento"? Rispetto a, ad esempio, copiare il file?

Se si dispone di molta memoria (ad es. 4 GB o più), quanto tempo occorre per cancellare il file una seconda volta, quando potrebbe trovarsi nella cache del file system?

+0

Ho eseguito alcuni test di velocità. Controlla il mio aggiornamento. Anche l'utilizzo della CPU raggiunge solo il 30% circa. –

+1

@Bruce: 30% in totale? Di quanti core? Se si tratta di una CPU multi-core ma un algoritmo di hashing a thread singolo, potrebbe comunque essere associato alla CPU. Guarda la scheda delle prestazioni del Task Manager per vedere se una CPU è ancorata per tutto il tempo :) –

+0

No, tutti e 4 i core hanno una media di circa il 5 - 6%. 2 core stanno facendo un po 'di lavoro ma da nessuna parte vicino a pegged. Sicuramente legato all'IO? –

1

Prima di tutto, hai misurato "abbastanza lento"? Da this site, SHA-1 ha circa la metà della velocità di MD5 con circa 100 MB/s (a seconda della CPU), quindi 2 GB richiederebbero circa 20 secondi per l'hash. Inoltre, si noti che se si utilizza un HDD lento, questo potrebbe essere il vero collo di bottiglia poiché 30-70 MB/s non sono inusuali.

Per accelerare le cose, si potrebbe semplicemente non hash l'intero file, ma il primo X KB o parti rappresentabili di esso (le parti che molto probabilmente differiscono). Se i tuoi file non sono troppo simili, questo non dovrebbe causare duplicati.

1

Primo: l'hashing del file SHA-1 deve essere legato all'I/O su CPU non antiche - e I5 certamente non si qualifica come antico. Ovviamente dipende dall'implementazione di SHA-1, ma dubito che SHA1Managed sia troppo lento.

Successivamente, 60 secondi per dati da 2 GB è ~ 34 MB/s - è lento per le letture del disco rigido; anche un disco da 2,5 "può leggere più velocemente di quello: supponendo che l'hard disk sia interno (nessun collo di bottiglia USB2/o di rete), e non c'è molta altra attività di I/O su disco, sarei sorpreso di vedere meno di 60 MB/s lettura da un'unità moderna.

mio ipotesi sarebbe che ComputeHash() utilizza un buffer piccolo internamente. Provate manualmente lettura/hashing, in modo da poter specificare un buffer più grande (64kb o anche più) per aumentare il throughput. È potrebbe anche passare alla elaborazione asincrona così disco di lettura e di calcolo può essere sovrapposta.

-1

è possibile utilizzare questa logica per ottenere SHA-1 valore. lo stavo usando in Java.

0.123.

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

Né è SHA1Managed la scelta migliore per i grandi stringhe di input, e non è Byte.ToString ("X2") il modo più veloce per convertire la matrice di byte in una stringa.

Ho appena terminato un articolo con benchmark dettagliati su questo argomento. Confronta SHA1Managed, SHA1CryptoServiceProvider, SHA1Cng e considera anche SHA1.Create() su stringhe di input di lunghezza diversa.

Nella seconda parte, mostra 5 diversi metodi per convertire l'array di byte in stringa dove Byte.ToString ("X2") è il peggiore.

Il mio input più grande era di soli 10.000 caratteri, quindi potresti voler eseguire i miei benchmark sul tuo file da 2 GB. Sarebbe piuttosto interessante se/come questo cambi i numeri.

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

Tuttavia, per i controlli di integrità del file si sta meglio con MD5 come già scritto.

Problemi correlati