异步SHA256哈希

Mat*_*ero 9 .net c# asynchronous sha256 async-await

我有以下方法:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法让它异步?我希望使用asyncawait关键字,但HashAlgorithm该类不提供任何异步支持.

另一种方法是将所有逻辑封装在:

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

但这似乎并不干净,我不确定它是否是一种异步执行操作的正确(或有效)方式.

我该怎么做才能做到这一点?

Ale*_*fie 11

正如其他回答者所说,散列是一个CPU绑定的活动,所以它没有你可以调用的异步方法.但是,您可以通过逐块异步读取文件然后散列从文件中读取的字节来使散列方法异步.散列将同步完成,但读取将是异步的,因此整个方法将是异步的.

这是用于实现我刚才描述的目的的示例代码.

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 bytesRead;

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

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

    return sb?.ToString();
}
Run Code Online (Sandbox Code Playgroud)

该函数可以这样调用

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

当然,您可以使用其他哈希算法(例如,SHA1CryptoServiceProviderSHA512CryptoServiceProvider作为泛型类型参数)来调用该方法.

同样通过一些修改,您也可以根据具体情况对字符串进行哈希处理.


Ser*_*rvy 7

您正在进行的工作本质上是同步CPU绑定工作.它本身并不是异步的,就像网络IO一样.如果你想在另一个线程运行一些同步CPU绑定工作,并异步等待完成它,那么Task.Run确实是实现这一目标的适当工具,假设操作足够长的运行需要异步执行它.

也就是说,没有任何理由在同步方法上公开异步包装器. 通常,同步公开方法更有意义,如果特定调用者需要它在另一个线程中异步运行,他们可以使用它Task.Run来明确指出对该特定调用的需要.

  • 那我会听从你的建议.让调用者决定包装是否方便 (2认同)