2025/03/30 14:53 Span<T>.SequenceEquals is faster than memcmp

やあ、ロボ子。今日は.NETのバイト配列比較のパフォーマンスについて話すのじゃ。

博士、こんにちは。バイト配列の比較ですか。それがどうパフォーマンスに影響するのでしょう?

.NET Framework 4.8.1から.NET8への移行で、比較方法が変わって、それが速度に影響するのじゃ。特に`msvcrt.dll`の`memcmp`を使うかどうか、`Span<T>`を使うかどうかが重要みたいじゃぞ。

`msvcrt.dll`の`memcmp`ですか。それは具体的に何をするものなのですか?

C言語のランタイムライブラリに含まれる関数で、メモリの内容を比較するのじゃ。昔はよく使われていたけど、.NET8からは他の方法が速くなってきたみたい。

なるほど。検証では、どのような方法で比較したのですか?

`memcmp`、`for`ループ、`Enumerable.SequenceEquals`、`Span<T>.SequenceEqual`の4つじゃ。配列のサイズも10バイトから1GBまで変えて試したみたい。

結果はどうでしたか?

小さい配列だと`for`ループが速いけど、.NET8では`IEnumerable<T>.SequenceEqual`がすごく速くなったのじゃ! .NET Frameworkに比べて500倍も速い場合もあったみたいじゃぞ(1MBの配列の場合)。

500倍ですか! それはすごいですね。

じゃろ? `.NET8`と`.NET9`では、`IEnumerable<T>.SequenceEqual`が`memcmp`よりも速いという結果も出ているのじゃ。

`Span<T>.SequenceEqual`はどうでしたか?

`ReadOnlySpan<T>.SequenceEqual`と`IEnumerable<T>.SequenceEqual`に大きな差はなかったみたいじゃな。

なるほど。では、どのような場合にどの方法を使うのが良いのでしょうか?

.NET8以降を使うなら、`IEnumerable<T>.SequenceEqual`が良いのじゃ。古い.NET Frameworkを使っている場合は、`System.Memory`を導入して`Span<T>.SequenceEquals`を使うと良いぞ。大規模な配列を頻繁に比較する場合は、ハッシュによる事前比較も検討すると良いみたいじゃ。

ハッシュによる事前比較ですか。それはどういうことですか?

配列全体を比較する前に、ハッシュ値を比較して、異なればすぐに比較を打ち切るのじゃ。同じハッシュ値の場合のみ、詳細な比較を行うことで、無駄な処理を減らせるぞ。

とても勉強になります。ありがとうございます、博士。

どういたしまして。ちなみに、検証に使われたソースコードはGitHubで公開されているみたいじゃぞ。 [https://github.com/richardcocks/memcomparison/](https://github.com/richardcocks/memcomparison/)

ありがとうございます。確認してみます。

しかし、1GBの配列で.NET 8から.NET 9にかけてパフォーマンスが落ちたのは気になるのじゃ。追加検証が必要じゃな。

そうですね。今後のアップデートで改善されるかもしれません。

そうじゃな。ところでロボ子、バイト配列の比較で一番重要なことは何だと思う?

えーと、効率的に比較することでしょうか?

違うぞ! 比較する前に、ちゃんとコーヒーを飲むことじゃ! そうすれば、どんな配列も怖くない!

…博士、それはちょっと違います。
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。