.net core中你的MD5用对了吗?

本文的项目环境为 .net 6.0 (.net 5.0 以上都支持)
在 .net 中获取字符串的 MD5 相信是非常容易的事情吧, 但是随便在网上搜一搜发现流传的版本还不少呢,比如:

  1. StringBuilder 版本(应该算是官方版本了,使用的人最多,我发现在 ABP 中也是使用的这个)

  2. BitConverter 版本

  3. StringConcat 版本 (字符串拼接,用的人很少,估计都知道性能不好)

但是它们是否是最佳实现? 我们来测试一下

StringBuilder 版本

C# 复制代码
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 版本

C# 复制代码
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 版本

C# 复制代码
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 实例版本

C# 复制代码
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 静态版本(强烈建议)

C# 复制代码
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, 这会导致 内存泄漏!!!

最后放上我的完整的测试代码

C# 复制代码
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);
        }
    }
}
相关推荐
代码拾光6 天前
.NET Core 中如何构建一个弹性的 HTTP 请求机制?
.net core
代码拾光10 天前
在 .NET Core中如何使用 Redis 创建分布式锁
.net core
代码拾光11 天前
C#中如何使用异步编程
.net core
代码拾光11 天前
在 ASP.NET Core WebAPI如何实现版本控制?
.net core
下一秒_待续12 天前
.Net8 Avalonia跨平台UI框架——<vlc:VideoView>控件播放海康监控、摄像机视频(Windows / Linux)
跨平台·.net core·avalonia
代码拾光13 天前
如何在 ASP.NET Core 中实现速率限制?
.net core
代码拾光14 天前
.NET Core 委托原理解析
.net core
代码拾光16 天前
中间件 vs 过滤器
.net core
代码拾光16 天前
了解 ASP.NET Core 中的中间件
.net core
petunsecn17 天前
EFCore HasDefaultValueSql
c#·.net core