dotnetcore / AgileConfig

基于.NET Core开发的轻量级分布式配置中心 / .NET Core lightweight configuration server
MIT License
1.5k stars 299 forks source link

Optimize MD5 performance #140

Closed InCerryGit closed 1 year ago

InCerryGit commented 1 year ago

In this PR, two things have been done:

1.Standardize file names 2.Optimize MD5 performance

We can reuse the MD5 instance. In fact, in .NET Core, it is already safe to reuse the MD5 instance.

In addition, we can change the hexadecimal conversion to a higher-performance Convert.ToHexString. The following are the results of the performance test, showing a 3-fold performance improvement:

BenchmarkDotNet=v0.13.5, OS=Windows 11 (10.0.22621.1928/22H2/2022Update/SunValley2)
13th Gen Intel Core i9-13900H, 1 CPU, 20 logical and 14 physical cores
.NET SDK=7.0.304
  [Host]     : .NET 7.0.7 (7.0.723.27404), X64 RyuJIT AVX2
  DefaultJob : .NET 7.0.7 (7.0.723.27404), X64 RyuJIT AVX2

|       Method |     Mean |   Error |  StdDev |   Gen0 | Allocated |
|------------- |---------:|--------:|--------:|-------:|----------:|
|       MD5Old | 524.5 ns | 4.79 ns | 4.00 ns | 0.0839 |    1056 B |
|       MD5New | 350.7 ns | 2.07 ns | 1.94 ns | 0.0267 |     336 B |
| MD5StaticNew | 171.6 ns | 1.89 ns | 1.77 ns | 0.0165 |     208 B |

Test Code:

using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;

for (int i = 0; i < 100; i++)
{
    var str = $"abc{i}";
    var staticNew = MD5Benchmark.Md5StaticNew(str); 
    var old = MD5Benchmark.Md5Old(str);
    var @new = MD5Benchmark.Md5New(str);

    Debug.Assert(old == @new);
    Debug.Assert(old == staticNew);
}

[Orderer]
[MemoryDiagnoser]
public class MD5Benchmark
{

    [Benchmark]
    public void MD5Old()
    {
        _ = MD5Benchmark.Md5Old("Benchmark");
    }

    [Benchmark]
    public void MD5New()
    {
        _ = MD5Benchmark.Md5New("Benchmark");
    }

    [Benchmark]
    public void MD5StaticNew()
    {
        _ = MD5Benchmark.Md5StaticNew("Benchmark");
    }

    public static string Md5Old(string txt)
    {
        using (var md5 = MD5.Create())
        {
            var inputBytes = Encoding.ASCII.GetBytes(txt);
            var hashBytes = md5.ComputeHash(inputBytes);

            // Convert the byte array to hexadecimal string
            var sb = new StringBuilder();
            for (var i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("X2"));
            }
            return sb.ToString();
        }
    }

    public static string Md5New(string txt)
    {
        using var md5 = MD5.Create();
        var inputBytes = Encoding.ASCII.GetBytes(txt);
        var hashBytes = md5.ComputeHash(inputBytes);
        return Convert.ToHexString(hashBytes);
    }

    private static readonly MD5 Md5 = MD5.Create();
    public static string Md5StaticNew(string txt)
    {
        var inputBytes = Encoding.ASCII.GetBytes(txt);
        var hashBytes = Md5.ComputeHash(inputBytes);
        return Convert.ToHexString(hashBytes);
    }
}
kklldog commented 1 year ago

Great! Thanks Shi zong!