hIp*_*pPy 4 c# hash multithreading
我无法得到这个问题的明确答案,所以这个问题。过去很少有 SO 帖子提到HashAlgorithmMSDN 文档中的实例不是线程安全的引用片段。
看
但是,当前的 MSDN 文档并没有这么说。令人惊讶的是,下面的代码在net3.1、net5.0上不会爆炸,但在net6.0上却会爆炸。所以,看起来它是线程安全的(也许),但也许 net6.0 有一个错误。
//<TargetFrameworks>net6.0;net5.0;netcoreapp3.1;net48</TargetFrameworks>
[Explicit]
[Test]
public void Bork_HashAlgorithm()
{
const int iterations = 1_000_000;
var bytes = Encoding.UTF8.GetBytes("the overtinkerer");
using (var md5 = MD5.Create())
{
Parallel.For(0, iterations, (i, loop) =>
{
md5.ComputeHash(bytes);
});
}
}
Run Code Online (Sandbox Code Playgroud)
异常消息:
SafeHandle 不能为空。(参数“pHandle”)
Ale*_*lex 13
不,它不是线程安全的。
我们在峰值负载下看到了相同的异常:SafeHandle cannot be null. (Parameter 'pHandle')MD5 提供程序、SHA1 和 SHA256 到处都出现类似的错误。
然而我们发现使用HashAlgorithma 的“单例”实例仍然是有益的lock,它仍然比每次创建单独的实例快 3 倍。
这是基准
| 方法 | 意思是 | 错误 | 标准差 | 0代 | 第一代 | 第二代 | 已分配 |
|---|---|---|---|---|---|---|---|
| MD5重建 | 1,282.5 纳秒 | 726.26纳秒 | 39.81纳秒 | 0.0801 | 0.0286 | 0.0038 | 512B |
| MD5单例带锁 | 402.2纳秒 | 39.38纳秒 | 2.16纳秒 | 0.0610 | - | - | 384 乙 |
| MD5_哈希数据 | 467.7纳秒 | 33.26纳秒 | 1.82纳秒 | 0.0548 | - | - | 344乙 |
这是代码:
static MD5 _md5 = MD5.Create(); // <-- one instance for all threads
public static byte[] MD5Hash(byte[] input)
{
lock (_md5) // <-- use a lock
{
return _md5.ComputeHash(input);
}
}
Run Code Online (Sandbox Code Playgroud)
更新:MD5_HashData是 .NET 5 中引入的新静态MD5.HashData方法 - 它并不比使用lock. 然而,MD5.HashData在高度并行性下表现出更好的性能,这是 BDN 无法模拟的(请参阅下面的评论)
UPDATE2:添加 SHA256 基准
| 方法 | 意思是 | 错误 | 标准差 | 0代 | 第一代 | 已分配 |
|---|---|---|---|---|---|---|
| 共享重建 | 2.211 我们 | 3.7097 我们 | 0.2033我们 | 0.1144 | 0.0534 | 736B |
| SHASingletonWithLock | 1.231 我们 | 0.1349 微秒 | 0.0074我们 | 0.0954 | - | 608乙 |
| SHA_HashData | 1.296 我们 | 0.0737 微秒 | 0.0040我们 | 0.0877 | - | 552 乙 |