2014-11-25 26 views
5

ho il seguente metodo:asincrono SHA256 hashing

public static string Sha256Hash(string input) { 
    if(String.IsNullOrEmpty(input)) return String.Empty; 
    using(HashAlgorithm algorithm = new SHA256CryptoServiceProvider()) { 
     byte[] inputBytes = Encoding.UTF8.GetBytes(input); 
     byte[] hashBytes = algorithm.ComputeHash(inputBytes); 
     return BitConverter.ToString(hashBytes).Replace("-", String.Empty); 
    } 
} 

C'è un modo per rendere asincrona? Speravo di usare async e attendere le parole chiave, ma la classe HashAlgorithm non fornisce alcun supporto asincrono per questo.

Un altro approccio è stato quello di incapsulare tutta la logica in una:

public static async string Sha256Hash(string input) { 
    return await Task.Run(() => { 
     //Hashing here... 
    }); 
} 

Ma questo non sembra pulito e non sono sicuro se è un modo corretto (o efficiente) per eseguire un'operazione in modo asincrono.

Cosa posso fare per ottenere questo risultato?

+2

Perché stai provando a farlo in modo asincrono? –

+0

@CoryNelson Non lo so onestamente. Ho pensato che avrei ottimizzato il codice facendolo girare in modo asincrono o su un altro thread. Ma le risposte mi schiarirono la mente. –

+0

@CoryNelson: mi sono imbattuto recentemente in una situazione in cui avevo bisogno di fare questo in modo asincrono per mantenere un'interfaccia utente reattiva mentre calcolavo l'hash di un file di grandi dimensioni. –

risposta

6

Il lavoro che si sta svolgendo è un lavoro legato alla CPU intrinsecamente sincrono. Non è intrinsecamente asincrono poiché qualcosa come l'IO di rete sarà. Se si desidera eseguire un lavoro sincronizzato della CPU sincrono in un altro thread e attendere in modo asincrono il completamento, allora lo Task.Run è effettivamente lo strumento appropriato per farlo, supponendo che l'operazione sia sufficientemente lunga da eseguire per eseguirla in modo asincrono.

That said, there really isn't any reason to expose an asynchronous wrapper over your synchronous method. Si rende generalmente più senso per esporre solo il metodo in modo sincrono, e se un particolare chiamante ha bisogno per funzionare in modo asincrono in un altro thread, possono utilizzare Task.Run per indicare esplicitamente che bisogno per quel particolare invocazione.

+2

Seguirò il tuo consiglio allora. E lascia che il chiamante decida se un wrapper è conveniente o meno –

1

L'overhead di eseguire questo in modo asincrono (utilizzando Task.Run) sarà probabilmente più alto che solo eseguendolo in modo sincrono.

Un'interfaccia asincrona non è disponibile perché è un'operazione associata alla CPU. Puoi renderlo asincrono (usando Task.Run) come hai fatto notare, ma ti consiglio di non farlo.

1

Come dichiarato dagli altri responder, l'hashing è un'attività legata alla CPU, quindi non è possibile chiamare i metodi Async. Tuttavia, è possibile rendere asincrono il proprio metodo di hashing tramite in modo asincrono leggendo il blocco di file per blocco e quindi eseguendo l'hashing dei byte letti dal file. L'hashing verrà eseguito in modo sincrono ma la lettura sarà asincrona e, di conseguenza, l'intero metodo sarà asincrono.

Ecco un esempio di codice per il raggiungimento dello scopo che ho appena descritto.

public static async Threading.Tasks.Task<string> GetHashAsync<T>(this Stream stream) 
    where T : HashAlgorithm, new() 
{ 
    StringBuilder sb; 

    using (var algo = new T()) 
    { 
     var buffer = new byte[8192]; 
     int read; 

     // compute the hash on 8KiB blocks 
     while ((read = await stream.ReadAsync(buffer, 0, buffer.Length)) == buffer.Length) 
      algo.TransformBlock(buffer, 0, read, buffer, 0); 
     algo.TransformFinalBlock(buffer, 0, read); 

     // build the hash string 
     sb = new StringBuilder(algo.HashSize/4); 
     foreach (var b in algo.Hash) 
      sb.AppendFormat("{0:x2}", b); 
    } 

    return sb?.ToString(); 
} 

La funzione può essere richiamata come tali

using (var stream = System.IO.File.OpenRead(@"C:\path\to\file.txt")) 
    string sha256 = await stream.GetHashAsync<SHA256CryptoServiceProvider>(); 

Naturalmente, si potrebbe ugualmente chiamare il metodo con altri algoritmi hash come SHA1CryptoServiceProvider o SHA512CryptoServiceProvider come parametro di tipo generico.

Allo stesso modo con alcune modifiche, è anche possibile ottenere per hash una stringa come è specifico per il tuo caso.