【C#】ボックス化のコストを文字列補間と string.Format で計測してみた

C#のボックス化のコストを、文字列補間とstring.Formatで計測してみました。
計測環境は以下の3つです。

  • .Net6
  • .Net Core 3.1
  • .Net Framework 4.8

上記3環境で、以下の4パターンを計測しました。

  1. 文字列補間 – ボックス化あり
  2. 文字列補間 – ボックス化なし
  3. string.Format – ボックス化あり
  4. string.Format – ボックス化なし

ボックス化とは

値型(intなど)をobject型に変換することを指します。
なお、object型から値型に変換することをアンボックス化と言います。

int n = 1;
object obj = n;   //ボックス化
int m = (int)obj; //アンボックス化

詳しくは以下の説明されています。

まとめ

まずは結果の概要から。

  1. .Netの早い順は「.Net 6 > .Net Core 3.1 > .Net Framework 4.8
  2. ボックス化ありの場合、文字列補間もstring.Formatもパフォーマンスは変わらない。
  3. ボックス化なしの場合、文字列補間の方がstring.Formatよりも高速
    これは、コンパイラが以下のようにコードを変換しているから。
    $"A{i.ToString()}B"

    "A" + i.ToString() + "B"
  4. .Net Framework 4.8の場合、ボックス化ありの方が遅いが、.Net Core3.1以降だと逆の結果となる。とはいえ、.Net Framework 4.8もたいして速度は変わらないので、あまり気にする必要はなさそう。

計測用コード

1000万回のループに何秒かかるかを計測します。

int cnt = 10000000;

var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < cnt; i++) {
    string tmp = $"A{i}B";
}
sw.Stop();
Console.WriteLine($"文字列補間 box/unbox化あり : {sw.ElapsedMilliseconds}");

sw.Restart();
for (int i = 0; i < cnt; i++) {
    string tmp = $"A{i.ToString()}B";
}
sw.Stop();
Console.WriteLine($"文字列補間 box/unbox化なし : {sw.ElapsedMilliseconds}");

sw.Restart();
for (int i = 0; i < cnt; i++) {
    string tmp = string.Format("A{0}B", i);
}
sw.Stop();
Console.WriteLine($"string.format box/unbox化あり : {sw.ElapsedMilliseconds}");

sw.Restart();
for (int i = 0; i < cnt; i++) {
    string tmp = string.Format("A{0}B", i.ToString());
}
sw.Stop();
Console.WriteLine($"string.format box/unbox化なし : {sw.ElapsedMilliseconds}");

計測結果

ボックス化文字列補間string.Format
.Net6あり393ms392ms
なし289ms436ms
.Net Core 3.1あり683ms664ms
なし429ms738ms
.Net Framework 4.8あり1180ms1144ms
なし761ms1127ms

終わりに

.Net は進化のたびに、しっかりとパフォーマンスが向上していてすごいなという印象を受ける。
新しく作るなら、新しいバージョンを積極的に導入していきたい。

文字列補間とstring.Formatは、できるだけ文字列補間を選ぶ方がパフォーマンス的には良さそう。可読性もこちらの方が良いし。

ボックス化の有無は、文字列補間とstring.Formatに関しては、事前にToStringをつける必要はなさそう。

コメント

タイトルとURLをコピーしました