本文的專案環境為 .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();
}
}