我不能得到一个明确的答案,所以这个问题。过去有几个SO帖子提到HashAlgorithm
的实例不是线程安全的MSDN文档中的引用片段。
看
- 为什么SHA1。ComputeHash在多线程的高负载下失败?
- HMACSHA1.ComputeHash()线程安全问题
- 哪段代码性能更好?
但是,当前的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);
});
}
}
异常信息:
SafeHandle不能为空。(参数pHandle)
不,它不是线程安全的。
我们在峰值负载下看到相同的异常:SafeHandle cannot be null. (Parameter 'pHandle')
和MD5提供商,SHA1和SHA256的类似错误,到处都是。
然而,我们发现使用"单例"仍然是有益的。用lock
创建HashAlgorithm
的实例,它仍然比每次创建一个单独的实例快3倍。
这是基准
md5re | 1,282.5 ns | 726.26 ns | 39.81 ns | 0.0801 | 0.0286 | 0.0038 | > 512 B |
MD5SingletonWithLock | 402.2 ns | 39.38 ns | 2.16 ns | 0.0610 | 384 B | ||
MD5_HashData | 467.7 ns | 33.26 ns | 1.82 ns | 0.0548 | 344 B |