😃

.NET6でいつの間にかGuidがreadonly structになっていた

2022/05/14に公開

パフォーマンス改善のために導入されたreadonly structですが、その改善は長らくGuid構造体には適用されていませんでした。
UUIDの.NET標準の実装であるGuid構造体は何かと使う機会も多かったので、この改善がいつになったら適用されるのかな~と首を長くして待っていたのですが、.NET6でreadonly structになっていることについ先日気が付きました。

いったいいつの間に…と思いちょっと調べてみたら.NET6からreadonlyになったようです。
https://github.com/dotnet/runtime/commit/43f63d70bfbb31fe128dc0da2e4a786d74d514f5#diff-6c4386bf60da64f68ecb306e3f0acbaba7e752b4bce7224d7c1725b28a60ed04R21
2年前の11月にコミットが入っていますね。

ベンチマーク

さてreadonly structになったということはin引数で渡したときのパフォーマンスが改善されることが期待されます。.NET5と.NET6でどれだけ差が出ているのか、早速ベンチを取ってみましょう。
コードは以下のようにしてみました。
できるだけin引数の差だけ確認したいのと、最適化によるメソッド呼び出し削除を抑制するため、Guidのメソッドで一番処理が軽そうなToByteArrayを呼び出して戻り値を取得しています。

using System;
using BenchmarkDotNet.Attributes;

namespace GuidBench
{
    [MemoryDiagnoser]
    public class Benchmarks
    {
        public static byte[] ToByteArrayNormal(Guid id) => id.ToByteArray();

        public static byte[] ToByteArrayIn(in Guid id) => id.ToByteArray();

        private readonly Guid _id = Guid.NewGuid();

        [Benchmark]
        public byte[] ToByteArrayNormal() => ToByteArrayNormal(_id);

        [Benchmark]
        public byte[] ToByteArrayIn() => ToByteArrayIn(_id);
    }
}

ベンチマークの結果

// * Summary *

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.22000
11th Gen Intel Core i5-11400F 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=6.0.300
  [Host]     : .NET Core 5.0.17 (CoreCLR 5.0.1722.21314, CoreFX 5.0.1722.21314), X64 RyuJIT
  DefaultJob : .NET Core 5.0.17 (CoreCLR 5.0.1722.21314, CoreFX 5.0.1722.21314), X64 RyuJIT
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
ToByteArrayNormal 3.976 ns 0.0299 ns 0.0249 ns 0.0064 - - 40 B
ToByteArrayIn 3.960 ns 0.0272 ns 0.0255 ns 0.0064 - - 40 B
// * Summary *

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.22000
11th Gen Intel Core i5-11400F 2.60GHz, 1 CPU, 12 logical and 6 physical cores
.NET Core SDK=6.0.300
  [Host]     : .NET Core 6.0.5 (CoreCLR 6.0.522.21309, CoreFX 6.0.522.21309), X64 RyuJIT
  DefaultJob : .NET Core 6.0.5 (CoreCLR 6.0.522.21309, CoreFX 6.0.522.21309), X64 RyuJIT
Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
ToByteArrayNormal 4.058 ns 0.0360 ns 0.0319 ns 0.0064 - - 40 B
ToByteArrayIn 3.690 ns 0.0350 ns 0.0327 ns 0.0064 - - 40 B

.NET5では通常の引数でもin引数でもパフォーマンスに差がありませんが、.NET6では1割ほど改善されています。
うれしい改善ですね。これからはin引数で渡していきましょう。

Discussion