ページ

2004年5月25日火曜日

文字列比較のパフォーマンス

どうやら、一部で流行っているようなので...(^^;



String s1 と String s2 があった場合に、両者が同じかどうかを比較するには



  1. s1.Equals(s2)
  2. String.Equals(s1, s2)
  3. s1 == s2

という 3種類の方法があります。
で、「どれが一番速いのよ?」 という話題ですね。


以下は sscli のソースと .NET Framework 1.1 をちょっと覗き見た内容です。


まず、3 の s1 == s2 は単に 2の String.Equals(s1, s2) を呼び出すだけです。
注意:  VB.NET の s1 = s2 は Microsoft.VisualBasic.CompilerServices.StringType.StrCmp を呼び出すそうですが、C# では単に String.operator ==(s1, s2) を呼び出すだけです。ちなみに、operator== は op_Equality とも表記されます(というか、IL 的には op_Equality のほうが正式名だと思いますが)。


次に、2 の String.Equals(s1, s2) ですが、これは
 a. s1 と s2 が同じオブジェクトなら true を返す。
 b. s1 か s2 が null なら false を返す。
 c. どちらでもないときは 1 の s1.Equals(s2) を呼び出す。
となっています。


で、1 は internalcall といって .NET Framework の内部に実装された関数にマップされています。


というわけで、どれが一番速いかは明らかですね。3 は 2 を呼び、2 は 1 を呼ぶ、という実装なんですから、1 が一番速くて 3 が一番遅いということになります。


ただ、ちょっと注意があります。s1、s2 が同じオブジェクトだった場合、もしくは、どちかが null だった場合は 2 が一番速いという結果になることが多いんじゃないかと思います。
ここで、C# だと同じ文字列定数は自動的に同じオブジェクトになります。それは以下のようにすれば確認できます。


string s1 = "aaa";
string s2 = "aaa";
if ((object)s1 == (object)s2) {
    Console.WriteLine("同じオブジェクト");
}

同じ文字列だけど別のオブジェクトを生成したいときは StringBuilder を使ってやればいいようです。


StringBuilder sb1 = new StringBuilder("aaa");
string s1 = sb1.ToString();
StringBuilder sb2 = new StringBuilder("aaa");
string s2 = sb.ToString();
if ((object)s1 == (object)s2)
{
    Console.WriteLine("同じオブジェクト");
}

# 1つの StringBuilder から 2回 ToString() してやっても別々のオブジェクトに
# なるようではありますが。

2 件のコメント:

  1. >IL 的には op_Equality のほうが正式名だと思いますが


    のはずですね。

    Managed C++ でマネージドクラスの演算子をオーバーロードする時は、op_xxx な関数をオーバーロードします。


    >同じ文字列だけど別のオブジェクトを生成したいときは StringBuilder を使ってやればいいようです。


    同一内容の文字列リテラルが同じオブジェクトで表わされるのはコンパイラの機能ですね。

    コンパイル時に同一内容の文字列がかき集められて一意なオブジェクトで置換されます。

    返信削除
  2. ありがとうございます

    さっそく、テストプログラムを更新しました

    String s1 = new StringBuilder("xxxx").ToString();

    String s2 = new StringBuilder("xxxx").ToString();

    として、文字列を作成するようにしました。

    返信削除