.net core中你的MD5用对了吗?
本文的项目环境为 .net 6.0 (.net 5.0 以上都支持)
在 .net 中获取字符串的 MD5 相信是非常容易的事情吧, 但是随便在网上搜一搜发现流传的版本还不少呢,比如:
-
StringBuilder
版本(应该算是官方版本了,使用的人最多,我发现在 ABP 中也是使用的这个) -
BitConverter
版本 -
StringConcat
版本 (字符串拼接,用的人很少,估计都知道性能不好)
但是它们是否是最佳实现? 我们来测试一下
StringBuilder 版本
public static string Md5_StringBuilder(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var hashByte in hashBytes)
{
sb.Append(hashByte.ToString("X2"));
}
return sb.ToString();
}
BitConverter 版本
public static string Md5_BitConverter(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
return BitConverter.ToString(hashBytes).Replace("-", "");
}
StringConcat 版本
public static string Md5_StringConcat(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
var output = string.Empty;
foreach (var hashByte in hashBytes)
{
output += hashByte.ToString("X2");
}
return output;
}
性能对比
先上我测试得到的数据(本机配置: 4 核 8 线程, 测试结果可能不一致)
Benchmark
看结果,的确是字符串拼接性能最差,但是
StringBuilder
好像也不是很高效啊,那个什么 Static 是啥玩意,怎么性能这么好,相对于 StringBuilder, 单线程性能提高了 3 倍, 多线性提高了 5 倍???
没错,这就是我要说的, 从 .net 5.0 开始提供了 2 个非常高效的方法
Convert.ToHexString
MD5.HashData
Convert.ToHexString 实例版本
public static string MD5_HexConvert_Instance(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
return Convert.ToHexString(hashBytes);
}
MD5.HashData 静态版本(强烈建议)
public static string MD5_HexConvert_Static(string input)
{
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = MD5.HashData(inputBytes);
return Convert.ToHexString(hashBytes);
}
总结
-
强烈建议 使用
MD5.HashData
+Convert.ToHexString
, 代码性能最高,也最简洁,只有 3 行 -
一定不要 忘记释放 MD5,我看网上很多在使用实例版本
MD5.Create()
后都没有 Dispose, 这会导致 内存泄漏!!!
最后放上我的完整的测试代码
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using System.Text;
using System.Security.Cryptography;
namespace ConsoleTest;
[SimpleJob(RuntimeMoniker.Net60)]
[MemoryDiagnoser(true)]
public class MD5_BenchMarks
{
[Params(10_0000)]
public int Size { get; set; }
[Benchmark]
[Arguments("123456")]
public string Md5_StringBuilder(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
var sb = new StringBuilder();
foreach (var hashByte in hashBytes)
{
sb.Append(hashByte.ToString("X2"));
}
return sb.ToString();
}
[Benchmark]
[Arguments("123456")]
public string Md5_StringConcat(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
var output = string.Empty;
foreach (var hashByte in hashBytes)
{
output += hashByte.ToString("X2");
}
return output;
}
[Benchmark]
[Arguments("123456")]
public string Md5_BitConverter(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
return BitConverter.ToString(hashBytes).Replace("-", "");
}
[Benchmark]
[Arguments("123456")]
public string MD5_HexConvert_Instance(string input)
{
using var md5 = MD5.Create();
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = md5.ComputeHash(inputBytes);
return Convert.ToHexString(hashBytes);
}
[Benchmark]
[Arguments("123456")]
public string MD5_HexConvert_Static(string input)
{
var inputBytes = Encoding.UTF8.GetBytes(input);
var hashBytes = MD5.HashData(inputBytes);
return Convert.ToHexString(hashBytes);
}
}
class Program
{
static void Main()
{
BenchmarkRunner.Run(typeof(MD5_BenchMarks));
Console.ReadKey();
}
}