简体   繁体   English

异步 SHA256 哈希

[英]Asynchronous SHA256 Hashing

I have the following method:我有以下方法:

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

Is there a way to make it asynchronous?有没有办法让它异步? I was hoping to use the async and await keywords, but the HashAlgorithm class does not provide any asynchronous support for this.我希望使用asyncawait关键字,但HashAlgorithm类不为此提供任何异步支持。

Another approach was to encapsulate all the logic in a:另一种方法是将所有逻辑封装在一个:

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

But this does not seem clean and I'm not sure if it's a correct (or efficient) way to perform an operation asynchronously.但这似乎并不干净,我不确定这是否是异步执行操作的正确(或有效)方法。

What can I do to accomplish this?我能做些什么来实现这一目标?

As stated by the other answerers, hashing is a CPU-bound activity so it doesn't have Async methods you can call.正如其他回答者所说,散列是一种受 CPU 限制的活动,因此它没有您可以调用的异步方法。 You can, however, make your hashing method async by asynchronously reading the file block by block and then hashing the bytes you read from the file.但是,您可以通过异步地逐块读取文件,然后对从文件中读取的字节进行哈希处理来使哈希方法异步。 The hashing will be done synchronously but the read will be asynchronous and consequently your entire method will be async.散列将同步完成,但读取将是异步的,因此您的整个方法将是异步的。

Here is sample code for achieving the purpose I just described.这是用于实现我刚刚描述的目的的示例代码。

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

The function can be invoked as such该函数可以这样调用

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

Of course,you could equally call the method with other hash algorithms such as SHA1CryptoServiceProvider or SHA512CryptoServiceProvider as the generic type parameter.当然,您也可以使用其他哈希算法(例如SHA1CryptoServiceProviderSHA512CryptoServiceProvider作为泛型类型参数调用该方法。

Likewise with a few modifications, you can also get it to hash a string as is specific to your case.同样,通过一些修改,您还可以根据您的情况对字符串进行哈希处理。

The work that you're doing is inherently synchronous CPU bound work.您正在做的工作本质上是同步的 CPU 绑定工作。 It's not inherently asynchronous as something like network IO is going to be.它不像网络 IO 那样本质上是异步的。 If you would like to run some synchronous CPU bound work in another thread and asynchronously wait for it to be completed, then Task.Run is indeed the proper tool to accomplish that, assuming the operation is sufficiently long running to need to perform it asynchronously.如果您想在另一个线程中运行一些同步 CPU 绑定的工作并异步等待它完成,那么Task.Run确实是完成该任务的合适工具,假设该操作运行时间足够长,需要异步执行它。

That said, there really isn't any reason to expose an asynchronous wrapper over your synchronous method. 也就是说,确实没有任何理由在同步方法上公开异步包装器。 It generally makes more sense to just expose the method synchronously, and if a particular caller needs it to run asynchronously in another thread, they can use Task.Run to explicitly indicate that need for that particular invocation.通常只同步公开方法更有意义,如果特定调用者需要它在另一个线程中异步运行,他们可以使用Task.Run显式指示需要该特定调用。

The overhead of running this asynchronously (using Task.Run) will probably be higher that just running it synchronously.异步运行(使用 Task.Run)的开销可能会高于同步运行。

An asynchronous interface is not available because it is a CPU bound operation.异步接口不可用,因为它是 CPU 绑定操作。 You can make it asynchronous (using Task.Run) as you pointed out, but I would recommend against it.正如您所指出的,您可以使其异步(使用 Task.Run),但我建议您不要这样做。

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

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