繁体   English   中英

异步 SHA256 哈希

[英]Asynchronous 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);
    }
}

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

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

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

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

我能做些什么来实现这一目标?

正如其他回答者所说,散列是一种受 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();
}

该函数可以这样调用

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

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

同样,通过一些修改,您还可以根据您的情况对字符串进行哈希处理。

您正在做的工作本质上是同步的 CPU 绑定工作。 它不像网络 IO 那样本质上是异步的。 如果您想在另一个线程中运行一些同步 CPU 绑定的工作并异步等待它完成,那么Task.Run确实是完成该任务的合适工具,假设该操作运行时间足够长,需要异步执行它。

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

异步运行(使用 Task.Run)的开销可能会高于同步运行。

异步接口不可用,因为它是 CPU 绑定操作。 正如您所指出的,您可以使其异步(使用 Task.Run),但我建议您不要这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM