.net core中你的MD5用對了嗎?

Broadm發表於2023-10-26

本文的專案環境為 .net 6.0 (.net 5.0 以上都支援)

在 .net 中獲取字串的 MD5 相信是非常容易的事情吧, 但是隨便在網上搜一搜發現流傳的版本還不少呢,比如:

  1. StringBuilder 版本(應該算是官方版本了,使用的人最多,我發現在 ABP 中也是使用的這個)

  2. BitConverter 版本

  3. 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 執行緒, 測試結果可能不一致)

image

Benchmark

image

看結果,的確是字串拼接效能最差,但是 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();
    }
}


相關文章