Skip to content

文字列の比較に string.Compare を使うのは遅すぎる #191

@ufcpp

Description

@ufcpp

Nameの比較など、文字列の比較をことごとくすべて、0 == string.Compare(x, y)で行っているようですが、これがかなりパフォーマンスネックになっていて困っています。

C# の場合、文字列の比較は==で十分です。また、==string.Compareでは10倍くらい性能差があります。

using System;
using System.Diagnostics;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        var testData = GetTestData().Result;

        var sw = new Stopwatch();

        // 試しに、単語列の中からtheの数をカウントするのでパフォーマンス確認

        // とりあえず100回同じ処理するのにかかる時間を測定。
        // string.Compare が遅すぎて、100で十分だった
        const int N = 100;
        int count = 0;

        // == で比較
        // C# の string の == はちゃんと中身の比較。
        // 最終的に行きつくコードはこれ: https://referencesource.microsoft.com/#mscorlib/system/string.cs,11648d2d83718c5e
        // 1文字1文字の単純比較。ポインターを使った最適化あり。
        sw.Start();
        for (int i = 0; i < N; i++)
        {
            count = 0;
            foreach (var word in testData)
            {
                if (word == "the") count++;
            }
        }
        sw.Stop();
        Console.WriteLine(count);
        Console.WriteLine(sw.Elapsed);

        sw.Reset();
        sw.Start();
        // string.Compare で比較
        // こっちはこれ: https://referencesource.microsoft.com/#mscorlib/system/globalization/compareinfo.cs,1356715f78447ed6
        // 正規化してから比較するかとか、大文字・小文字は区別するかとか、空白を除いて比較するかとか、いろいろ余計なオプションがついてる。
        // 半端なく遅い。
        for (int i = 0; i < N; i++)
        {
            count = 0;
            foreach (var word in testData)
            {
                // さっきとの違いはこの行の if の中身だけ
                if (0 == string.Compare(word, "the")) count++;
            }
        }
        sw.Stop();
        Console.WriteLine(count); // 結果は一緒。
        Console.WriteLine(sw.Elapsed); // == と比べて10倍くらい遅かった…
    }

    // 何か適当な文字列を取ってきて、スペースでSplit
    private static async Task<string[]> GetTestData()
    {
        var c = new HttpClient();
        var res = await c.GetAsync("https://en.wikipedia.org/wiki/Microsoft");
        var content = await res.Content.ReadAsStringAsync();
        return content.Split(' ');
    }
}

しかも、例えばScript_SpriteStudio_DataAnimation の中など、結構高頻度で呼ばれる上にforループの中にこの処理があるため、顕著にパフォーマンス劣化が見られます。

Compareを呼ぶとか余計な真似をせず、素直できれいなコードに書き直すだけで10倍近い改善がみられるので、直してはもらえないでしょうか。

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions