- A+
所属分类:.NET技术
本文的项目环境为 .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 线程, 测试结果可能不一致)
看结果,的确是字符串拼接性能最差,但是
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 System.Text; using System.Security.Cryptography; using System.Diagnostics; namespace ConsoleTest; class Program { 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(); } 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; } 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("-", ""); } 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); } public static string MD5_HexConvert_Static(string input) { var inputBytes = Encoding.UTF8.GetBytes(input); var hashBytes = MD5.HashData(inputBytes); return Convert.ToHexString(hashBytes); } private const int LOOPCOUNT = 100_0000; private static void CalcTime(Func<string, string> func, bool parallel = true) { Stopwatch stopwatch = Stopwatch.StartNew(); if (parallel) { Parallel.For(0, LOOPCOUNT, i => { func("123456"); }); } else { for (int i = 0; i < LOOPCOUNT; i++) { func("123456"); } } stopwatch.Stop(); Console.WriteLine($"{func.Method.Name,32}: {stopwatch.ElapsedMilliseconds,4}ms"); } static void Main() { Test(); Console.ReadKey(); } private static void Test() { var functions = new List<Func<string, string>> { Md5_StringConcat, Md5_StringBuilder, Md5_BitConverter, MD5_HexConvert_Instance, MD5_HexConvert_Static, }; foreach (var func in functions) { Console.WriteLine($"{func.Method.Name,32}: {func("123456")}"); } Console.WriteLine($"n单线程 {LOOPCOUNT} 次用时统计:"); foreach (var func in functions) { CalcTime(func, false); } Console.WriteLine($"n多线程 {LOOPCOUNT} 次用时统计:"); foreach (var func in functions) { CalcTime(func, true); } } }